Virtual method calls and member data: vtables

The key to PODS is the object's virtual function table. This is the mechanism by which a virtual method call is resolved to an actual function invocation. A vtable (some authors prefer vtbl) is simply a list of all the virtual methods on an object, organized in such a way that a call expecting to see a parent class' vtable will work without changes on a child class' vtable. In C++, simply declaring a class as inheriting from another class tells the compiler to do this work. In C, you have to write the code explicitly.

For a concrete example, suppose we have the following C++ declarations:

class Base
{
protected:
     int               x, y;
public:
     Base(int xx, int yy);
     virtual ~Base();

     int               GetX();
     int               GetY();
     virtual int       Sum();
     virtual float     GetMean();
     virtual void      Set(int xx, int yy);
};

class Child : public Base
{
protected:
     float             mean;
public:
     Child(int xx, int yy);
     virtual ~Child();

     virtual float     GetMean();
     virtual void      Set(int xx, int yy);
     virtual float     Schematize();
}

The corresponding declarations in C, as done by PODS, would be as shown below.

Note

Except for PODSPod, no PODS object type has any data members, so the parent data struct type is not declared for them in the real header files.

typedef struct Base Base; // forward
struct BaseVTable
{
    void  (*Destroy)(Base *self); // see next
                                  // section
    int   (*Sum)(Base *self);
    float (*GetMean)(Base *self);
    void  (*Set)(Base *self, int xx, int yy);
};
struct BaseData
{
    int                x, y;
};
struct Base
{
    struct BaseVTable  *vtable;
    struct BaseData    basedata;
};

extern Base *BaseNew(int xx, int yy); // see next
                                      // section
extern int BaseGetX(Base *self);
extern int BaseGetY(Base *self);

#define PODSsum(b)      (*(b->vtable->Sum))(b)
#define PODSgetMean(b)  (*(b->vtable->GetMean))(b)
#define PODSset(b,xx,yy)(*(b->vtable->Set))(b,xx,yy)

typedef struct Child Child;         // forward
struct ChildVTable
{
    // recapitulate BaseVTable
    void   (*Destroy)(Child *self); // see next
                                    // section
    int    (*Sum)(Child *self);
    float  (*GetMean)(Child *self);
    void   (*Set)(Child *self, int xx, int yy);
    // add new methods
    void   (*Schematize)(Child *self);
};
struct ChildData
{
    float  mean;
};
struct Child
{
    struct ChildVTable  vtable;
    struct BaseData     basedata;
    struct ChildData    childdata;
};
extern Child *ChildNew(int xx, int yy); // see
                                   // next section

#define PODSschematize(c)(*(c->vtable->Schematize))©)