Bat*_*eba 13 c++ language-lawyer
考虑
struct base {};
struct child : base {};
Run Code Online (Sandbox Code Playgroud)
众所周知,sizeof(child)通过应用空基优化可以是1 .
但是现在考虑一下
struct base {};
struct child : base {base b;};
Run Code Online (Sandbox Code Playgroud)
编译器现在可以应用空基优化,还是必须sizeof(child)至少为2?
the*_*rge 18
不,它不能.来自同一参考:
如果其中一个空基类也是第一个非静态数据成员的类型或基类,则禁止空基本优化
因此sizeof(child) >= 2.
Max*_*kin 16
规则是相同类型的子对象不能在同一地址.X这里有2 个子对象,因此每个子对象必须位于不同的地址.
由于C++中对象的标识是其地址,因此相同类型的对象不能共享相同的地址.如果相同类型的多个对象共享相同的地址,则它们是无法区分的.这就是最小完整对象大小为1的原因,因此数组中的每个对象都有一个不同的地址.请参阅"§C++对象模型[intro.object]":
对象是存储区域.
...
对象可以包含其他对象,称为子对象.子对象可以是成员子对象(9.2),基类子对象(子句10)或数组元素.不是任何其他对象的子对象的对象称为完整对象.
...
除非它是位字段(9.6),否则最派生的对象应具有非零大小并且应占用一个或多个存储字节.基类子对象可以具有零大小.
...
除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址.如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址; 否则,他们应有不同的地址.
这就是为什么,例如,boost::noncopyable如果通过空基类间接地无意间地继承它,可以增加类的大小.例如:
struct A : boost::noncopyable {};
struct B : boost::noncopyable {};
struct C : boost::noncopyable {};
struct D : A, B, C {};
Run Code Online (Sandbox Code Playgroud)
sizeof(D) == 3因为有三个不同的boost::noncopyable子科目.如果boost::noncopyable删除派生,那么sizeof(D) == 1.
Nic*_*las 14
C++中的对象需要具有唯一的"身份".来自[intro.object]/8(N4659):
如果一个对象嵌套在另一个对象中,或者如果至少有一个是零大小的基类子对象并且它们的类型不同,那么两个对象
a并且b具有不是位字段的重叠生存期可以具有相同的地址; 否则,他们有不同的地址.
基类子对象和成员子对象是单独的对象; 两者都没有"嵌套"在另一个之内.因此,如果它们属于同一类型,则它们必须具有单独的地址.
请注意,这会递归地延伸.考虑以下:
struct eb1 {};
struct eb2 : eb1 {};
struct not_empty(eb1 a;};
struct derived : eb2 {not_empty b;};
Run Code Online (Sandbox Code Playgroud)
由于C++的唯一标识规则,derived::eb2::eb1 必须有不同的地址derived::b::a.因此,编译器不能使用EBO derived.
我将推出另一个更基本的报价
如果一个嵌套在另一个中,则具有不是位字段的重叠生存期的两个对象a和b可以具有相同的地址,或者如果至少一个是零大小的基类子对象并且它们具有不同类型,则它们可以具有相同的地址.否则,他们有不同的地址.
由于b不是继承的子对象base,因此它们必须具有不同的地址.