There is this code:
#include <iostream>
class Base
{
int x;
};
class Derived : virtual public Base
{
int y;
};
int main()
{
std::cout << sizeof(Derived) << std::endl; // prints 12
return 0;
}
I have read that when some class is virtually inherited then there is created empty vtable for class Derived, so memory layout is as follows:
Derived::ptr to empty vtable
Derived::y
Base::x
and it is 12 bytes. The question is - what is purpose of this empty vtable if there are not any virtual methods and how is it used?
Derived
needs some way to know where theBase
subobject is. With virtual inheritance, the relative location of the base class is not fixed with respect to the location of the derived class: it may be located anywhere in the full object.Consider a more typical example involving diamond inheritance.
Here, both
B1
andB2
derive virtually fromA
, so inC
, there is exactly oneA
subobject. BothB1
andB2
need to know how to find thatA
subobject (so that they can access thea
member variable, or other members ofA
if we were to define them).This is what the vtable is used for in this case: both
B1
andB2
will have a vtable that contains the offset of theA
subobject.To demonstrate what a compiler might do to implement the above diamond inheritance example, consider the following class layouts and virtual tables, generated by the Visual C++ 11 Developer Preview.
and the following vtables:
Note that the offsets are relative to the address of the vtable, and note that for the two vtables generated for the
B1
andB2
subobjects ofC
, the offsets are different.(Also note that this is entirely an implementation detail--other compilers may implement virtual functions and bases differently. This example demonstrates one way that they are implemented, and they are very commonly implemented this way.)