基础结构的虚拟继承

nab*_*bil 3 c++ struct structure virtual-inheritance

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() {}
};
Run Code Online (Sandbox Code Playgroud)

你能否解释为什么在C结构中会有两个A :: i以及为什么会有两个vptr指针指向C结构的'虚表表方法',尽管A只有虚方法?我知道当从一个公共基地有虚拟继承时,会有一个共同基础的实例而不是两个,请指教!

Mis*_*sch 13

没有虚拟
没有继承时virtual,你可以想象内存结构是这样的:

class B : A {};
Run Code Online (Sandbox Code Playgroud)

没有虚拟的继承

变量A是"内部"(正上方)类的变量B.

使用虚拟
继承时virtual,B只需要一个"指针" A:

class B : virtual A {};
Run Code Online (Sandbox Code Playgroud)

用虚拟继承

您的示例
这意味着,您的示例如下所示:

class B : A
class C : B, virtual A
Run Code Online (Sandbox Code Playgroud)

你的榜样

只有一个实例A 如果你只想要一个实例A,你必须使用virtual两次:

class B : virtual A
class C : B, virtual A
Run Code Online (Sandbox Code Playgroud)

只有一个A的实例

的vptr的

下面是代码的布局,因为它是由g ++(生成的-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)
Run Code Online (Sandbox Code Playgroud)

关于vpointers和vtables,我有点生疏,所以我不确定为什么会有那些v-pointers.

但是,我可以告诉你,你假设只有一种虚方法是错误的.因为B继承自A并且A::f()是虚拟的,所以派生B::f()自动也是虚拟的,即使您没有明确地将其写下来.

编辑:

挖了一下之后,我想我还记得哪些是需要的指针,哪些不是.但是,我不会对您提供以下任何保证.
在下文中,符号C.B.A表示A-subobject Bin C,用于区分两个子A对象(C.B.AC.A).

每个子类都需要一个v-pointer.然而*(C.B.A),*(C.B)*C都指向同一个位置(类即开始C,这也是年初C.BC.B.A,因此它们可以共享一个vpointer.但是一个指向子类*(C.A)将指向不同的位置,因此另一个vpointer是需要注意的是,C.B.A在你的例子中甚至无法访问子类(gcc:"警告:直接基础''由于歧义而在'C'中无法访问'".

为了使它更清楚:
如果你只有以下结构

class B : A {};
class C : B {};
Run Code Online (Sandbox Code Playgroud)

因为所有指向任何子类的指针C都指向同一位置,所以只需要一个vpointer .vpointer只需要指向任一个的vtable A,B或者C告诉哪个是对象的运行时类型.