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?
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.