在fedora-linux上用gcc 4.8.2
和llvm/clang 3.4
编译我的代码为C ++ 11,我得到了奇怪的结果,我无法解释......
这是一个类似的程序fedora。
#include <iostream>
using namespace std;
struct A {};
struct C {};
struct B1 : A { union { A a;}; };
struct B2 : A { union { C c;}; };
int main()
{
cout << sizeof(B1) << " " << sizeof(B2) << endl;
}
sizeof(B1) = 2
和sizeof(B2) = 1
但为什么尺寸不同?实际上我有一个想法&#34;为什么&#34;,但我想找到确切的解释或C ++规则。
答案 0 :(得分:6)
B1
子项同时包含A
类型的父对象和子对象。同一类型的两个不同对象不能存在于同一地址,并且union分别包含对父A
的额外A
。
使用B2
,空基础优化允许空的A
父级和C
成员共享子级的单个地址。
答案 1 :(得分:2)
我认为C ++标准中有两个有用的引用。第一个定义了什么是子对象。
2个对象可以包含其他对象,称为子对象。一个子对象 可以是成员子对象(9.2),基类子对象(第10条), 或数组元素。
第二个说同一类型的两个子对象可能没有相同的地址
基类子对象的大小可以为零(第9条);然而,两个 具有相同类类型且属于同一类的子对象 大多数派生对象不得分配在同一地址(5.10)。 - 后注]
所以在这个类定义中
struct B1 : A { union { A a;}; };
有两个类型为A的子对象:基类子对象和成员子对象a。
此外,重要的是要添加每个匿名联盟的每个成员都是包含匿名联合的类的成员。
答案 2 :(得分:1)
可以将C ++ 11标准解释为允许两个示例的大小为1:
1.8 C ++对象模型§6:
除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址。两个不同的对象既不是位字段也不是零大小的基类子对象应具有不同的地址。
对于案例1,至少有一个非规范性通知不允许它,但它是非规范性的:
10派生类§8:
[注意:基类子对象可能具有与同一类型的大多数派生对象的布局不同的布局(3.7)。基类子对象可能具有与同一类型的大多数派生对象的多态行为不同的多态行为(12.7)。基类子对象可以是零大小(第9条);但是,必须不在同一地址(5.10)分配具有相同类类型且属于同一最多派生对象的两个子对象。 - 后注]
最新的公开草案(n3797日期为2013-10-13)虽然不允许第一个例子的大小为1:
1.8 C ++对象模型§6:
除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址;否则,他们应有不同的地址。
答案 3 :(得分:0)
谢谢你们快速回复!!!我用模板技巧修改了我的代码,以便实际对象的数据相同,但模板类型不同 - 工作完美!!!对于那些感兴趣的人,现在它看起来像这样(T不能等于零):
template<int T> struct A { enum{ val = T < 0 ? -T : T}; };
struct B1 : A<1> { union { A<-1> a;}; };
谢谢