// -*- c++ -*- // C++ code class Mammal { virtual void ProduceMilk(); virtual void GiveLiveBirth(); virtual void GenerateHeat(); }; class Dog : public Mammal { void ProduceMilk() override; virtual void Bark(); }; class Cat : public Mammal { virtual void Meow(); }; class Exotherm { virtual void ProduceMilk() = 0; }; // C code struct Mammal_vtable { void(*ProduceMilk)(Mammal*); void(*GiveLiveBirth)(Mammal*); void(*GenerateHeat)(Mammal*); }; const struct Mammal_vtable Mammal_vtable = { Mammal_ProduceMilk, Mammal_GiveLiveBirth, Mammal_GenerateHeat }; struct Mammal { const struct Mammal_vtable* vtable; // always points to Mammal_vtable }; struct Dog_vtable { Mammal_vtable Mammal_vtable; void(*Bark)(Dog*); }; const struct Dog_vtable Dog_vtable = { {Dog_ProduceMilk, Mammal_GiveLiveBirth, Mammal_GenerateHeat}, Dog_Bark }; struct Dog { // always points to Dog_vtable // note that if a Dog* is interpreted as a Mammal*, this is treated as a // Mammal_vtable*, which is okay because it starts with one const struct Dog_vtable* vtable; }; struct Cat_vtable { Mammal_vtable Mammal_vtable; void(*Meow)(Cat*); }; const struct Cat_vtable Cat_vtable = { {Mammal_ProduceMilk, Mammal_GiveLiveBirth, Mammal_GenerateHeat}, Cat_Meow }; struct Cat { // always points to Cat_vtable const struct Cat_vtable* vtable; }; struct Exotherm_vtable { void(*GenerateHeat)(Exotherm*); }; // no vtable actually exists directly for Exotherm since it is an abstract // class (contains at least one unimplemented virtual) struct Exotherm { Exotherm_vtable* vtable; }; // even though Mammal (and through it, Cat and Dog) has an // identically-prototyped GenerateHeat() to the one in Exotherm, there's no // way to "pun" a Dog, Cat, or Mammal into an Exotherm without their // cooperation // but, hypothetically, you could do: class CatExotherm : public Cat, public Exotherm {}; // and it would become something a bit like: struct CatExotherm_vtable1 { struct Cat_vtable Cat_vtable; }; struct CatExotherm_vtable2 { struct Exotherm_vtable Exotherm_vtable; }; const struct CatExotherm_vtable1 CatExotherm_vtable1 = { {{Mammal_ProduceMilk, Mammal_GiveLiveBirth, Mammal_GenerateHeat}, Cat_Meow} }; const struct CatExotherm_vtable2 CatExotherm_vtable2 = { {Mammal_GenerateHeat} }; struct CatExotherm { // the part it inherits from Cat (which goes first because we inherited from // Cat first) struct CatExotherm_vtable1* vtable1; // fields from Cat would go here // the part it inherits from Exotherm struct CatExotherm_vtable2* vtable2; // fields from Exotherm would go here }; // When using a CatExotherm* where an Exotherm* is expected, the pointer is // actually changed to point to the second part of CatExotherm; the part that // gets its layout from Exotherm rather than Cat.