consider following hierarchy:
struct { int a; a() { f(0); } a(int i) { f(i); } virtual void f(int i) { cout << i; } }; struct b1 : virtual { int b1; b1(int i) : a(i) { f(i); } virtual void f(int i) { cout << i+10; } }; struct b2 : virtual { int b2; b2(int i) : a(i) { f(i); } virtual void f(int i) { cout << i+20; } }; struct c : b1, virtual b2 { int c; c() : b1(6),b2(3),a(1){} virtual void f(int i) { cout << i+30; } }; what's exact memory layout of
cinstance? how many vptrs contains, each of them placed? of virtual tables shared virtual table of c? each virtual table contains?here how understand layout:
---------------------------------------------------------------- |vptr1 | aptrofb1 | b1 | b2ptr | c | vptr2 | aptrofb2 | b2 | | ----------------------------------------------------------------where
aptrofbxpointerainstancebxcontains (since inheritance virtual).
correct? functionsvptr1points to? functionsvptr2points to?given following code
c* c = new c(); dynamic_cast<b1*>(c)->f(3); static_cast<b2*>(c)->f(3); reinterpret_cast<b2*>(c)->f(3);why calls
fprint33?
virtual bases different ordinary bases. remember "virtual" means "determined @ runtime" -- entire base subobject must determined @ runtime.
imagine getting b & x reference, , tasked find a::a member. if inheritance real, b has superclass a, , b-object viewing through x has a-subobject in can locate member a::a. if most-derived object of x has multiple bases of type a, can see particular copy subobject of b.
but if inheritance virtual, none of makes sense. don't know which a-subobject need -- information doesn't exist @ compile time. dealing actual b-object in b y; b & x = y;, or c-object c z; b & x = z;, or entirely different derives virtually a many more times. way know find actual base a at runtime.
this can implemented 1 more level of runtime indirection. (note how entirely parallel how virtual functions implemented 1 level of runtime indirection compared non-virtual functions.) instead of having pointer vtable or base subobject, 1 solution store pointer to pointer actual base subobject. called "thunk" or "trampoline".
so actual object c z; may follows. actual ordering in memory compiler , unimportant, , i've suppressed vtables.
+-+------++-+------++-----++-----+ |t| b1 ||t| b2 || c || | +-+------++-+------++-----++-----+ | | | v v ^ | | +-thunk-+ | +--->>----+-->>---| ->>-+ +-------+ thus, no matter whether have b1& or b2&, first thunk, , 1 in turn tells find actual base subobject. explains why cannot perform static cast a& of derived types: information doesn't exist @ compile time.
for more in-depth explanation, take @ this fine article. (in description, thunk part of vtable of c, , virtual inheritance necessitates maintenance of vtables, if there no virtual functions anywhere.)
Comments
Post a Comment