A Study on object oriented Programming with plain old C
/** Object oriented programming with C 2005-08-03 */ #include <stdio.h> #include <stdlib.h> /** DATA OF BASECLASS: */ typedef struct { void * vtbl; /**< pointer to vtbl */ int a; /**< an example property */ } Alpha; /** final (non virtual) function: */ Alpha * alpha_add(Alpha *this, int da) { this->a += da; return this; }; /** virtal function: */ static char * alpha_toString(const Alpha *this, char *string) { sprintf(string, "%d", this->a); return string; }; /** virtual table of class Alpha */ typedef struct { char* (*toString)(const Alpha*, char*); /* add more vf's of Alpha here */ } Alpha_vtbl; static Alpha_vtbl s_alpha_vtbl= {alpha_toString}; #define Alpha_VTP(o) (*((Alpha_vtbl**)(o))) /** Constructor: */ Alpha * alpha_init(Alpha *this, int a) { Alpha_VTP(this) = &s_alpha_vtbl; this->a=a; return this; } /** DATA OF DERIVED CLASS: */ typedef struct { Alpha parent; /**< parent data */ int b; /**< one more property */ } Beta; /** overwrites virtal function alpha_toString: */ static char * beta_toString(const Alpha *this, char *string) { sprintf(string, "%d/%d", this->a, ((Beta*)this)->b); return string; }; /** new virtal function in class Beta (unknown in Alpha): */ static int beta_getTotal(const Beta *this) { return ((Alpha*)this)->a + this->b; }; /** virtual table of class Beta */ typedef struct { Alpha_vtbl parent; /**< all vf's of parent */ int (*getTotal)(const Beta *this); /**< new vf of Beta */ } Beta_vtbl; static Beta_vtbl s_beta_vtbl= {{beta_toString}, beta_getTotal}; #define Beta_VTP(o) (*((Beta_vtbl**)(o))) /** Constructor: */ Beta* beta_init(Beta *this, int a, int b) { alpha_init((Alpha*)this, a); // vtbl hast to be set _after_ Beta_VTP(this)= &s_beta_vtbl; // call of partent construcor!! this->b = b; return this; } /** DATA OF DERIVED DERIVED CLASS: */ typedef struct { Beta parent; /**< parent data */ int c; /**< one more property */ } Gamma; /** overwritten virtal function: */ static char * gamma_toString(const Alpha *this, char *string) { sprintf(string, "%d/%d/%d", this->a, ((Beta*)this)->b, ((Gamma*)this)->c); return string; }; /** overwrites virtal function: */ static int gamma_getTotal(const Beta *this) { return ((Alpha*)this)->a + this->b + ((Gamma*)this)->c; }; /** virtual table of class Gamma */ typedef struct { Beta_vtbl parent; /**< all vf's of parent */ } Gamma_vtbl; static Gamma_vtbl s_gamma_vtbl= {{{gamma_toString}, gamma_getTotal}} ; #define Gamma_VTP(o) (*((Gamma_vtbl**)(o))) /** Constructor: */ Gamma* gamma_init(Gamma *this, int a, int b, int c) { beta_init((Beta*)this, a, b); // vtbl hast to be set _after_ Gamma_VTP(this)= &s_gamma_vtbl; // call of partent construcor!! this->c = c; return this; } /** CLIENT: */ int main(void) { char strbf[100]; int i; Alpha alpha; Beta beta; Gamma gamma; Alpha *alphas[] = {&alpha, (Alpha*)&beta, (Alpha*)&gamma}; #define ALPHAS_CNT (sizeof alphas / sizeof alphas[0]) Beta *betas[] = {&beta, (Beta*)&gamma}; #define BETAS_CNT (sizeof betas / sizeof betas[0]) alpha_init(&alpha, 1); beta_init(&beta, 0, 2); alpha_add(alphas[1], 2); // example for call of final method of base class gamma_init(&gamma, 3,3,3); printf("call of vf toString() for all alphas:\n"); for (i=0; i<ALPHAS_CNT; i++) { Alpha_VTP(alphas[i])->toString(alphas[i], strbf); printf("alphas[%d]: %s\n", i, strbf); } printf("call of vf introduced in Beta getTotal() for all betas:\n"); for (i=0; i<BETAS_CNT; i++) { int s= Beta_VTP(betas[i])->getTotal(betas[i]); printf("beta[%d] sum= %d\n", i, s); } return 0; }