在多级继承中派生的虚拟基类会发生啥?

Posted

技术标签:

【中文标题】在多级继承中派生的虚拟基类会发生啥?【英文标题】:What happens to a virtual base class on being derived in multilevel inheritance?在多级继承中派生的虚拟基类会发生什么? 【发布时间】:2012-12-08 10:54:48 【问题描述】:

在玩继承时,我碰巧尝试了这个:

class A
 int i; ;

class B : virtual public A
 int j; ;

class C : public B
 int k; ;

int main()

    std::cout<<sizeof(C)/sizeof(int);
    return 0;

这给了我6的输出

虽然以下工作按预期提供输出3

class A
 int i; ;

class B : public A  // No virtual here
 int j; ;

class C : public B
 int k; ;

int main()

    std::cout<<sizeof(C)/sizeof(int);
    return 0;

为什么会有这种差异?而且,为什么它是第二种情况的两倍?

【问题讨论】:

【参考方案1】:

依赖于实现

但是,几乎所有编译器都将使用相同的机制,只要您有 virtual 关键字,编译器就需要通过 vptrvtables 进行一些额外的记账。这种额外的簿记增加了班级规模。

严格来说,您应该依赖大小来确定具体的大小,这就是标准提供sizeof 来获取实际大小而不是猜测它的原因。

【讨论】:

【参考方案2】:

很简单,虚拟继承涉及额外的开销。一个典型的实现至少需要一个额外的指针。

请参阅Virtual tables and virtual pointers for multiple virtual inheritance and type casting 中的问题 4 及其答案。

【讨论】:

【参考方案3】:
class A 
    int i;
;

class B : public A 
    int j;
;

在这个使用虚拟继承的例子中,B 类型的对象可以像 B 这样定义:

class B0 
    int i;
    int j;
;

一旦你引入了虚拟继承,这就行不通了:

class C : public virtual A 
    int k;
;

class D : public virtual A 
    int l;
;

class E : public C, public D 
    int m;
;

C 类型的对象有两个int 成员:k 来自C 的定义,i 来自A 的定义。同样,D 类型的对象有两个 int 成员,li。到现在为止还挺好。棘手的部分来自类E:它也有一个 int 成员i,因为A 的两个实例都是虚拟基。所以CD 都不能写成上面的B0,因为那样E 会得到两个 i 的副本。

解决方法是增加一层间接性。 CDE 类型的对象看起来像这样(伪代码,不要尝试编译):

class C0 
    int *cip = &i;
    int k;
    int i;
;

class D0 
    int *dip = &i;
    int l;
    int i;
;

class E0 
// C0 subobect:
    int *cip = &i;
    int k;
// D0 subobject:
    int *dip = &i;
    int l;
// E data:
    int *eip = &i;
    int m;
    int i;
;

您在E 的大小中看到的是那些额外的指针,无论CD 在派生类中如何组合,它们都可以拥有i 的单个副本。 (实际上,这些指针中的每一个都是指向A 的指针,因为A 肯定可以有多个数据成员,但这在这个简单的伪代码中很难表示)。

【讨论】:

int *cip = &amp;i; 你的意思是指向 C 中继承的成员 i 的指针?如果是这样,那么在虚拟继承中,实际上只有指针被继承,而不是具有相同名称的成员? @AshRj - 这个答案是关于实现细节的。不管虚拟继承如何实现,虚拟基的成员都是继承的;您可以通过派生类型的对象直接引用它们,而不必知道它们来自基类。【参考方案4】:

这取决于您的编译器的实现。不同的编译器有不同的结果。但是一个是肯定的,结果肯定不止三个。

【讨论】:

以上是关于在多级继承中派生的虚拟基类会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

C ++继承:具有基类类型的虚函数中派生类类型的参数

c++解决二义性的方法

生成一个派生类对象时,调用基类和派生类构造函数按啥次序

C++中派生类的构造函数怎么显式调用基类构造函数?

用视图控制器类继承视图:新类会实例化基类的 UI 对象吗?

C++中派生类重写基类重载函数时需要注意的问题:派生类函数屏蔽基类中同名函数