Virtual base classes implementations
Virtual base classes are exactly like virtual function: their address (or relative address aka offset) is not known at compile time:
void f(ClassB *pb) {
ClassA *pa = pb;
}
Here the compiler must compute the offset of the ClassA base subobject from the ClassB subobject (or mostly derived object). Some compiler simply have a pointer to it inside ClassB; others use the vtable, just like for virtual functions.
In both case the overhead in ClassB is one pointer.
The ClassC is similar, but the vptr will be point to a ClassC vtable, not a ClassB vtable.
Thus a ClassD object will contain (this is not an ordered list):
- a single
ClassA subobject
- a
ClassB subject
- a
ClassC subject
So ClassD has two inherited vptr: from ClassB and ClassC. In a ClassD object, both vptr will point to some ClassD vtable, but the same ClassD vtable:
- a
ClassB subject points to the ClassB-in-ClassD vtable, which indicates the relative position of ClassA base from ClassB base
- a
ClassC subject points to the ClassC-in-ClassD vtable, which indicates the relative position of ClassA base from ClassC base
Possible optimization
I guess your question is: do we need two distinct vptr?
Technically, it is sometimes possible to optimize the size of classes by overlaying base class subobjects. This is one of those cases where it is technically possible:
Overlaying (or unification) means that both ClassB and ClassC will share the same vptr: given d an instance of ClassD:
&d.ClassB::vptr == &d.ClassC::vptr so d.ClassB::vptr == d.ClassC::vptr but d.ClassB::vptr == &ClassC_in_ClassD_vtable and d.ClassC::vptr == &ClassC_in_ClassD_vtable, so ClassB_in_ClassD_vtable must be unified with ClassC_in_ClassD_vtable. In this particular case, both ClassB_in_ClassD_vtable and ClassC_in_ClassD_vtable are only used to describe the offset of ClassA subobject; if ClassB and ClassC subobjects are unified in ClassD, then these offsets are unified too, hence the unification of the vtables are possible.
Note that this is only possible here as there is perfect similarity. If ClassB and ClassC were modified to add even one virtual function in each, such as these virtual functions are not equivalent (hence not unifiable), the vtable unification would not be possible.
Conclusion
This optimization is only possible in very simple cases like this one. These cases are not typical of C++ programming: people normally use virtual base classes in combination with virtual functions. Empty base class optimization is useful because many C++ idioms use base classes with no data members or virtual functions. OTOH, a tiny (one vptr) space optimization for a special use of virtual base classes does not seem useful for real world programs.