I read this question: C++ Virtual class inheritance object size issue, and was wondering why virtual inheritance results in an additional vtable pointer in the class.
I found an article here: https://en.wikipedia.org/wiki/Virtual_inheritance
which tells us:
However this offset can in the general case only be known at runtime,...
I don't get what is runtime-related here. The complete class inheritance hierarchy is already known at compile time. I understand virtual functions and the use of a base pointer, but there is no such thing with virtual inheritance.
Can someone explain why some compilers (Clang/GCC) implement virtual inheritance with a vtable and how this is used during runtime?
BTW, I also saw this question: vtable in case of virtual inheritance, but it only points to answers related to virtual functions, which is not my question.
The complete class inheritance hierarchy is already known in compile time.
True enough; so if the compiler knows the type of a most derived object, then it knows the offset of every subobject within that object. For such a purpose, a vtable is not needed.
For example, if B
and C
both virtually derive from A
, and D
derives from both B
and C
, then in the following code:
D d;
A* a = &d;
the conversion from D*
to A*
is, at most, adding a static offset to the address.
However, now consider this situation:
A* f(B* b) { return b; }
A* g(C* c) { return c; }
Here, f
must be able to accept a pointer to any B
object, including a B
object that may be a subobject of a D
object or of some other most derived class object. When compiling f
, the compiler doesn't know the full set of derived classes of B
.
If the B
object is a most derived object, then the A
subobject will be located at a certain offset. But what if the B
object is part of a D
object? The D
object only contains one A
object and it can't be located at its usual offsets from both the B
and C
subobjects. So the compiler has to pick a location for the A
subobject of D
, and then it has to provide a mechanism so that some code with a B*
or C*
can find out where the A
subobject is. This depends solely on the inheritance hierarchy of the most derived type---so a vptr/vtable is an appropriate mechanism.