在多级继承中派生的虚拟基类会发生啥?
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
关键字,编译器就需要通过 vptr
和 vtables
进行一些额外的记账。这种额外的簿记增加了班级规模。
严格来说,您应该依赖大小来确定具体的大小,这就是标准提供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
成员,l
和 i
。到现在为止还挺好。棘手的部分来自类E
:它也有一个 int
成员i
,因为A
的两个实例都是虚拟基。所以C
和D
都不能写成上面的B0
,因为那样E
会得到两个 i
的副本。
解决方法是增加一层间接性。 C
、D
和 E
类型的对象看起来像这样(伪代码,不要尝试编译):
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
的大小中看到的是那些额外的指针,无论C
和D
在派生类中如何组合,它们都可以拥有i
的单个副本。 (实际上,这些指针中的每一个都是指向A
的指针,因为A
肯定可以有多个数据成员,但这在这个简单的伪代码中很难表示)。
【讨论】:
int *cip = &i;
你的意思是指向 C 中继承的成员 i 的指针?如果是这样,那么在虚拟继承中,实际上只有指针被继承,而不是具有相同名称的成员?
@AshRj - 这个答案是关于实现细节的。不管虚拟继承如何实现,虚拟基的成员都是继承的;您可以通过派生类型的对象直接引用它们,而不必知道它们来自基类。【参考方案4】:
这取决于您的编译器的实现。不同的编译器有不同的结果。但是一个是肯定的,结果肯定不止三个。
【讨论】:
以上是关于在多级继承中派生的虚拟基类会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章