Question

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!

Était-ce utile?

La solution

Without virtual
When inheriting without virtual, you can imagine the memory structure to be like this:

class B : A {};

Inheritance without virtual

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 {};

Inheritance with virtual

Your example
This means, your example looks like this:

class B : A
class C : B, virtual A

Your example

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

Only one instance of A

vptr's

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.

Autres conseils

B isn't inheriting virtualy.

So you have the A struct inherited from B and another inherited virtauly.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top