// Example with virtual and non-virtual functions, // subclasses, and overriding implemented in C // CSE 333 lecture demo, 3/16. HP // An object is a struct with instance variables and // (since there are virtual functions) a pointer to // the class vtable. #include #include //////////// Thing //////////// // Typedefs for Thing class objects and vtable typedef struct thing Thing; typedef struct thing_vtable Thing$vtable; // Thing object layout struct thing { Thing$vtable *vtbl; // vtable pointer int x_; // instance variable }; // Thing member functions - setX and getVal are virtual void Thing$setX(Thing *this, int x) { this->x_ = x; } int Thing$getVal(Thing* this) { return this->x_; } int Thing$getNum(Thing* this) { return this->x_; } // Thing vtable layout -- pointers to virtual functions struct thing_vtable { void (*setX)(Thing*, int); int (*getVal)(Thing*); }; // Thing vtable (initialized global data) static Thing$vtable Thing$vtbl = { &Thing$setX, &Thing$getVal }; // Combination new+constructor for Thing objects // return a new Thing with given x value Thing *Thing$new(int x) { // allocate object Thing *this = (Thing *)malloc(sizeof(Thing)); // initialize vtable this->vtbl = &Thing$vtbl; // initialize field this->x_ = x; // return pointer to new object return this; } //////////// Widget (subclass of Thing) //////////// // Typedefs for Widget subclass objects and vtable typedef struct widget Widget; typedef struct widget_vtable Widget$vtable; // Widget object layout struct widget { Widget$vtable *vtbl; // vtable pointer int x_; // superclass instance variable int y_; // widget instance variable }; // Widget member functions - setY and getVal are virtual void Widget$setY(Widget *this, int y) { this->y_ = y; } int Widget$getVal(Widget *this) { return this->y_; } int Widget$getNum(Widget *this) { return this->y_; } // Widget vtable layout - pointers to virtual functions // First two entries match order in superclass Thing struct widget_vtable { void (*setX)(Thing*, int); // inherited int (*getVal)(Widget*); // override void (*setY)(Widget*, int); // new in Widget }; // Widget vtable (initialized global data) static Widget$vtable Widget$vtbl = { &Thing$setX, &Widget$getVal, &Widget$setY }; // Combination new+constructor for Widget objects // return a new Widget with given x and y values Widget *Widget$new(int x, int y) { // allocate object Widget *this = (Widget *)malloc(sizeof(Widget)); // initialize vtable this->vtbl = &Widget$vtbl; // initialize fields this->x_ = x; this->y_ = y; // return pointer to new object return this; } //////////// main //////////// int main() { Thing *t1 = Thing$new(17); Widget *w = Widget$new(42, 333); Thing *t2 = (Thing*)w; // virtual function calls int n1 = t1->vtbl->getVal(t1); // t1->getVal(); int n2 = t2->vtbl->getVal(t2); // t2->getVal(); (same object as w) int n3 = w->vtbl->getVal(w); // w->getVal(); (same object as t2) printf("t1 val = %d, t2 val = %d, w val = %d\n", n1, n2, n3); // non-virtual function calls n1 = Thing$getNum(t1); // t1->getNum(); n2 = Thing$getNum(t2); // t2->getNum(); (same object as w) n3 = Widget$getNum(w); // w->getNum(); (same object as t2) printf("t1 num = %d, t2 num = %d, w num = %d\n", n1, n2, n3); return 0; }