Object oriented programming with C

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;
}