在多级继承中派生的虚拟基类会发生什么
What happens to a virtual base class on being derived in multilevel inheritance?
在处理继承时,我碰巧尝试了这个:
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;
}
为什么会有这种差异?为什么是第二种情况的两倍?
这取决于实现。
然而,几乎所有的编译器都会使用相同的机制,只要有virtual
关键字,编译器就需要通过vptr
和vtables
进行一些额外的记账。这种额外的记账增加了班级规模。
严格地说,你应该依赖大小来确定任何特定的大小,这就是为什么标准提供sizeof
来获得实际大小,而不是猜测估计它的原因。
很简单,虚拟继承涉及额外的开销。典型的实现至少需要一个额外的指针。
请参阅虚拟表和虚拟指针中的问题4,了解多个虚拟继承和类型转换以及答案。
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
成员:来自C
定义的k
和来自A
定义的i
。类似地,类型为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
当然可以有多个数据成员,但这在这个简单的伪代码中太难表示了)。
这取决于编译器的实现。不同的编译器有不同的结果。但有一点是肯定的,结果肯定不止三个。
相关文章:
- 使用基类指针调用基类的值构造函数的语法是什么?
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 与简单地创建派生类指针相比,将基类绑定到派生类有什么优点?
- 如果基类指针无法访问派生类成员函数,那么多态性有什么方便的呢?
- 私下继承C++抽象基类是什么意思
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- 调用不属于基类的派生类函数的最佳方法是什么?
- 子类的构造函数后跟冒号后的基类构造函数是什么意思?
- 抽象类的需求是什么?为什么要通过其基类访问派生类方法?在C++
- 在多级继承中派生的虚拟基类会发生什么
- 虚拟基类在多级继承中有什么用
- 我应该为接口还是抽象基类编程?该短语到底是什么意思
- 派生类对象是否包含基类的私有成员?它在记忆中是什么样子的
- 将派生类对象分配给基类对象时会发生什么(我的意思是对象断言,而不是指针)
- 基类的销毁顺序是什么
- 调用一个空基类函数,编译时会发生什么
- 当C++中都没有在基类中定义虚函数和纯虚函数时,虚拟函数和纯虚函数有什么区别
- STL 容器列表、deque、vector 等的基类是什么?
- 抽象基类有什么用
- 从派生类实现基类构造函数专用化的替代方法是什么