I am quite interested about virtual inheritance and this thing creates mystery for me. Let's consider an example with virtual inheritance:
struct Base {
virtual void v() { std::cout << "v"; }
};
struct IntermediateDerivedFirst : virtual Base {
virtual void w() { std::cout << "w"; }
};
struct IntermediateDerivedSecond : virtual Base {
virtual void x() { std::cout << "x"; }
};
struct Derived : IntermediateDerivedFirst, IntermediateDerivedSecond {
virtual void y() { std::cout << "y"; }
};
Finally, Derived should look like this:
--------
|[vtable]| -----> [ vbase offset 20 ]
|[vtable]|--- [ top offset 0 ]
|[vtable]|- | [ Derived typeinfo ]
-------- || [ IntermediateDerivedFirst::w() ]
|| [ Derived::y() ]
||
|----> [ vbase offset 12 ]
| [ top offset -8 ]
| [ Derived typeinfo ]
| [ IntermediateDerivedSecond::x()]
|
-----> [ vbase offset 0 ]
[ top offset -20 ]
[ Derived typeinfo ]
[ Base::v() ]
So, literally, virtual inheritance moves vtable for the most base class to the end and as we can see -- vtables for IntermediateDerivedFirst, IntermediateDerivedSecond do not contain address for Base's v() method. Okay, then, we can see that the class has few vtables.
Let's consider a code:
IntermediateDerivedFirst* fb = new Derived;
fb->v();
delete fb;
This invocation is still valid, however, vtable for IntermediateDerivedFirst has no info about v() method and it seems it uses some magic here and it uses third vtable pointer to invoke v().
So, how does the compiler choose needed vtable pointer to get an address of function being invoked?