[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In case of virtual bases, the code is even more complicated. Constructors and destructors need to know whether they are "in charge" of the virtual bases, and an implicit integer `__in_chrg' for that purpose.
struct A{ int i; virtual void bar(); void call_bar(){bar();} }; struct B:virtual A{ B(); int j; virtual void bar(); }; B::B(){ call_bar(); } struct C{ int k; }; struct D:C,B{ int l; virtual void bar(); }; |
When constructing an instance of B, it will have the following layout: `vbase pointer to A', `j', `A virtual table', `i'. On a 32-bit machine, downcasting from `A*' to `B*' would need to subtract 8, which would be the thunk executed when calling `B::bar' inside `call_bar'.
When constructing an instance of D, it will have a different layout: `k', `vbase pointer to A', `j', `l', `A virtual table', `i'. So, when downcasting from `A*' to `B*' in a `D' object, the offset would be `12'.
This means that during construction of the `B' base of a `D' object, a virtual table is needed which has a `-12' thunk to `B::bar'. This is only needed during construction and destruction, as the full object will use a `-16' thunk to `D::bar'.
In order to implement this, the compiler generates an implicit argument
(in addition to __in_chrg
): the virtual list argument
__vlist
. This is a list of virtual tables needed during
construction and destruction. The virtual pointers are ordered in the
way they are used during construction; the destructors will process the
array in reverse order. The ordering is as follows:
vfield
, and therefore require
more than one vtable
. The order of vtables is the same as used
when initializing vfields of non-virtual bases in a constructor.
The compiler emits a virtual table list in a variable mangled as
__vl.classname
.
Class with virtual bases, but without pvbases, only have the
__in_chrg
argument to their ctors and dtors: they don't have any
vfields in the vbases to initialize.
A further problem arises with virtual destructors: A destructor
typically has only the __in_chrg
argument, which also indicates
whether the destructor should call operator delete
. A dtor of a
class with pvbases has an additional argument. Unfortunately, a caller
of a virtual dtor might not know whether to pass that argument or not.
Therefore, the dtor processes the __vlist
argument in an
automatic variable, which is initialized from the class' vlist if the
__in_chrg flag has a zero value in bit 2 (bit mask 4), or from the
argument __vlist1
if bit 2 of the __in_chrg parameter is set to
one.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |