Search code examples
c++polymorphismmultiple-inheritancevirtual-functionsvtable

vtable and polymorphism - offset of a function


If I understand things correctly, a class definition imposes a certain order of the virtual functions in the vtable, and so a given function is known to be at a certain offset from the beginning of the table. However, I don't understand how that works with polymorphism.

class B1 {
  virtual void funcB1();
};

class B2 {
  virtual void funcB2() {}
};

class D : public B1, public B2 {
  virtual void funcB1() {}
  virtual void funcB2() {}
};

void main(...) {
  B1 *b1 = new D();
  B2 *b2 = new D();
  B1 *realB1 = new B1();
  B2 *realB2 = new B2();

  b1->funcB1();
  b2->funcB2();
  realB1->funcB1();
  realB2->funcB2();
}

How does the generated code know how to access funcB2 at different offsets?


Solution

  • When you compose a class from two base classes, each part is represented in the resultant class by a fully functioning block, complete with its own pointer to vtable. That is how the generated code knows what function to call: casting the pointer of D to B1 and B2 produces different pointers, so the generated code can use the same offset into the virtual table.

    D *d = new D();
    B1 *b1 = dynamic_cast<B1*>(d);
    B2 *b2 = dynamic_cast<B2*>(d);
    printf("%p %p %p", (void*)d, (void*)b1, (void*)b2);
    

    This produces the following output on ideone:

    0x91c7008 0x91c7008 0x91c700c
    

    Note how D* and B1* print the same value, while B2* prints a different value. When you call b2->funcB2(), the pointer b2 already points to a different part of the D object, which points to a different vtable (the one that has the layout of B2), so the generated code does not need to do anything differently for b2 vs realB2 in your example.