I was reading the Wikipedia article on virtual inheritance. I followed the whole article but I could not really follow the last paragraph
This is implemented by providing
Mammal and WingedAnimal with a vtable
pointer (or “vpointer”) since, e.g.,
the memory offset between the
beginning of a Mammal and of its
Animal part is unknown until runtime.
Thus Bat becomes
(vpointer,Mammal,vpointer,WingedAnimal,Bat,Animal).
There are two vtable pointers, one per
inheritance hierarchy that virtually
inherits Animal. In this example, one
for Mammal and one for WingedAnimal.
The object size has therefore
increased by two pointers, but now
there is only one Animal and no
ambiguity. All objects of type Bat
will have the same vpointers, but each
Bat object will contain its own unique
Animal object. If another class
inherits from Mammal, such as
Squirrel, then the vpointer in the
Mammal object in a Squirrel will be
different from the vpointer in the
Mammal object in a Bat, although they
can still be essentially the same in
the special case that the Squirrel
part of the object has the same size
as the Bat part, because then the
distance from the Mammal to the Animal
part is the same. The vtables are not
really the same, but all essential
information in them (the distance) is.
Can someone please shed some more light on this.
Sometimes, you just really need to see some code / diagrams 🙂 Note that there is no mention of this implementation detail in the Standard.
First of all, let’s see how to implement methods in C++:
This is similar to:
And in fact, when you look at a method call within a debugger, you’ll often see the
thisargument as the first parameter. It is sometimes called an implicit parameter.Now, on to the virtual table. In C and C++ it is possible to have pointers to function. A vtable is essentially a table of pointers to functions:
Now I can do something like:
Now, on to the inheritance. Let’s create another structure
And the use:
But how to automate this ?
Now, what happens in case of multi-inheritance ? Well, inheritance is very much like composition in term of memory layout:
There will thus be 2 virtual tables for
MostDerived: one to change the methods fromBaseAand one to change the methods fromBaseB.Pure virtual functions are generally represented as a null pointer (simply) in the corresponding field.
And finally, construction and destruction:
Construction
BaseAis constructed: first the vpointer is initialized, then the attributes, then the body of the constructor is executedBaseBis constructed: vpointer, attributes, bodyDerivedis constructed: replace the vpointers (both), attributes, bodyDestruction
Derived is destructed: body of the destructor, destroy attributes, put the base vpointers backBaseBis destructed: body, attributesBaseAis destructed: body, attributesI think it’s pretty comprehensive, I’d be glad if some C++ gurus around there could review this and check I haven’t made any stupid mistake. Also, if something is missing, I’d be glad to add it.