2017-06-19 75 views
3

我知道的是,空类的大小是1,只是为了符合不允许大小的对象(及其类)为0的标准。在这里,我得到了派生类D的大小为2.为什么行为在这种情况下是不同的 假设没有数据成员或虚拟指针从类B和C继承到D?为什么从两个空类派生的空类的大小是2?

#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

也许是因为它由两个大小为1的基类组成? –

+0

@o_weisman但实际上,这些基类的大小为0,只是为了每个对象被分配不同的内存,大小设置为1,与D类的情况相同,这应该是什么行为。 – cbinder

+1

@DrorMeirovich您提到的问题的参考资料是关于虚拟指针的,但在这种情况下,类是空白的,并且没有涉及数据成员(包括虚拟指针)的继承。 – cbinder

回答

3

对我来说,似乎无论是否空基地优化可以应用在这里,取决于如何解释[intro.object/8]

除非对象是一个位域或基类的子对象大小为零,那个对象的地址就是它所占用的第一个字节的地址。 两个对象一个,并用重叠的不 位字段寿命b 可以具有相同的地址,如果一个被嵌套在所述 其他,或者如果至少一个是零大小和 的基类子对象它们的不同类型;否则,他们有不同的地址。

BC不同类型?他们都是A。实际上有两个不同的A对象。允许编译器编写器分别在BC处单独停止分配存储,而不检查A是否为空。

值得一提的是,与G ++大小回到1,如果你有B独立基地C继承:

Live Example

#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; 
} 
2

这是因为你继承两个基类自己派生自相同的基类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

的问题是类似于可怕的钻石,你可能知道的。编译器试图在您的示例中消除D中存在的A这两个实例。而空基地优化这里不适用,该标准不要求它和编译器不执行(见下文)


该标准明确允许编译器不应用空基地优化多重继承的情况下。从标准here

相关报价允许标准布局类有基类强制编译器实现了标准布局类空基地优化,这可能会破坏编译器的应用程序二进制接口(ABI)。见上面9.2/18。这被认为不是现代编译器关心的问题,除了可能在多重继承的情况下。由于多重继承不是本建议的核心,因此如果证明存在争议,允许标准布局类或其基础使用多重继承将从提议中消除。

+0

我不认为有钻石相关的歧义,因为没有符号可以解决。 – cbinder

+0

@cbinder但它们都从相同的基类继承,当发生这种情况时,编译器不需要将基类视为空基,因为它需要消除这两个基的歧义。 – Curious

+0

@cbinder从标准中添加了一个引用 – Curious