我所知道的是,空类的大小为1只是为了符合不允许大小为0的对象(及其类)的标准。这里,我得到派生类D的大小为2。在这种情况下,为什么行为不同 假设没有从B类和C类继承的数据成员或虚拟指针到D?
#include<iostream>
using namespace std;
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
int main() {
cout<<"Size of D is: "<<sizeof(D)<<endl;
return 0;
}
答案 0 :(得分:3)
对我而言,似乎是否可以在此处应用空基础优化,取决于人们如何解释[intro.object/8]:
除非对象是位字段或基类子对象为零 size,该对象的地址是它的第一个字节的地址 占据。 两个对象 a和b,重复的生命周期不是 位字段可以具有相同的地址,如果其中一个嵌套在 其他,或者如果至少有一个是零大小的基类子对象 它们属于不同类型;否则,他们有不同的地址。
B
和C
是否有不同的类型?它们都是A
。实际上有两个不同的A
个对象。允许编译器编写者单独停在B
和C
的分配存储,而不检查A
是否为空。
值得注意的是,使用g ++,如果B
和C
继承自单独的基础,则大小会回到1:
#include<iostream>
class A {};
class A1 {};
class B : public A {};
class C : public A1 {};
class D : public B, public C {};
int main() {
std::cout << "Size of D is: " << sizeof(D) << std::endl;
return 0;
}
答案 1 :(得分:3)
这是因为您从两个基类继承而来自同一基类A
,看看当您将程序更改为此时输出如何变化
#include<iostream>
using namespace std;
class A {};
class Z {};
class B : public A {};
class C : public Z {};
class D : public B, public C {};
int main() {
cout<<"Size of D is: "<<sizeof(D)<<endl;
return 0;
}
如您所见,D
的尺寸为1
问题类似于你可能知道的可怕钻石的问题。编译器正在尝试消除示例中A
中存在的D
的两个实例的歧义。并且这里没有应用空基优化,标准不需要它,编译器也没有实现它(见下文)
标准明确允许编译器不对多继承情况应用空基优化。标准here
的相关引用允许标准布局类使基类强制编译器为标准布局类实现空基本优化,这可能会破坏编译器的应用程序二进制接口(ABI)。见上文9.2 / 18。这被认为不是现代编译器的关注点,除非可能存在多重继承。由于多重继承不是此提案的核心,因此如果证明有争议,将允许标准布局类或其基础使用多重继承。