Reputation: 914
struct A {
int i;
virtual void f() { cout << i; }
A() { i = 1; }
A(int _i) : i(_i) {}
};
struct B : A {
B() : A(2) { f(); }
void f() { cout << i+10; }
};
struct C : B, virtual A {
C() : A() {}
};
Can you please explain why in the C structure there will be two A::i and why there will be two vptr pointers to 'virtual tables methods' for C structure although A only has virtual method ? I know when there is virtual inheritance from a common base there will be one instance of the common base not two ,Please advise!
Upvotes: 3
Views: 14431
Reputation: 10880
Without virtual
When inheriting without virtual
, you can imagine the memory structure to be like this:
class B : A {};
The variables of A
are "inside" (just above) the variables of class B
.
With virtual
When inheriting with virtual
, B
just has a "pointer" to A
:
class B : virtual A {};
Your example
This means, your example looks like this:
class B : A
class C : B, virtual A
Only one instance of A
If you only want one instance of A
, you have to use virtual
two times:
class B : virtual A
class C : B, virtual A
Here is the layout of your code as it was produced by g++ (generated with -fdump-class-hierarchy
):
Class C
size=16 align=4
base size=8 base align=4
C (0xb7193440) 0
vptridx=0u vptr=((& C::_ZTV1C) + 12u)
B (0xb719f078) 0
primary-for C (0xb7193440)
A (0xb719a428) 0
primary-for B (0xb719f078)
A (0xb719a460) 8 virtual
vptridx=4u vbaseoffset=-12 vptr=((& C::_ZTV1C) + 28u)
I'm a bit rusty what concerns vpointers and vtables, so I'm not sure why there are exactly those v-pointers.
However, I can tell you, that your assumption that there is only one virtual method is wrong.
Because B
inherits from A
and A::f()
is virtual, the derived B::f()
is automatically also virtual, even if you don't explicitly write this down.
edit:
After digging a bit, I think I remember which v-pointers are needed and which are not.
However I won't give you any guarantee about the following.
In the following, the notation C.B.A
means the A
-subobject in B
, which is in C
, to distinguish the both A
-subobject (C.B.A
and C.A
).
Each subclass needs a v-pointer. However *(C.B.A)
, *(C.B)
and *C
all point to the same location (namely the beginning of the class C
which is also the beginning of C.B
and C.B.A
, therefore they can share one v-pointer. However a pointer to the subclass *(C.A)
will point to a different location, therefore another vpointer is needed there. Also note that the subclass C.B.A
won't even be accessible in your example (gcc: "warning: direct base ‘A’ inaccessible in ‘C’ due to ambiguity").
To make it a bit clearer:
If you only had the following structure
class B : A {};
class C : B {};
only one vpointer would be needed as all pointers to any subclass of C
would point to the same location. The vpointer would only have to point to the vtable of either A
, B
or C
to tell which is the run-time type of the object.
Upvotes: 17
Reputation: 49269
B isn't inheriting virtualy.
So you have the A struct inherited from B and another inherited virtauly.
Upvotes: 1