Pergunta

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!

Foi útil?

Solução

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.

Outras dicas

B isn't inheriting virtualy.

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top