Benutzer-Werkzeuge

Webseiten-Werkzeuge


becki:linux:oop_with_c

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;
}
  • no need to prefix data members by m_ , bcause they are always accessed with this→…
  • virtual functions must have the same interface troughout the hole hierarchy
  • only casts to parent class (not to child class) should be made on the client side
  • To call a virtual function always use the Xxx_VTP Macro to get a pointer to the virtual table
Cookies helfen bei der Bereitstellung von Inhalten. Diese Website verwendet Cookies. Mit der Nutzung der Website erklären Sie sich damit einverstanden, dass Cookies auf Ihrem Computer gespeichert werden. Außerdem bestätigen Sie, dass Sie unsere Datenschutzerklärung gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website. Weitere Information
becki/linux/oop_with_c.txt · Zuletzt geändert: 2010-05-05 10:20 von admin

Impressum - Datenschutzerklärung