C ++标准中的两个引号,§1.8:
对象是存储区域。
基类子对象的大小可能为零。
我不认为存储区域的大小为零。这意味着某些基类子对象实际上不是对象。这些陈述如何共存?
答案 0 :(得分:10)
关于“地区”定义的哲学论证是不必要的。
1.8 / 5说,“除非它是一个位字段,否则大多数派生对象的大小应为非零......基类子对象的大小可能为零”。因此标准非常清楚什么对象(以及因此“存储区域”)可以具有零大小。如果您不同意标准“英语区域”在英语中的含义,那么您可以错误地解释作者(非编程相关)的文学技巧。对于这个问题,你可以错过他们的诗歌技巧(14.7.3 / 7)但是很清楚标准在这里所说的类类型对象的大小。
阅读标准的实用方法是,对一个单词给出两个合理的解释,选择一个不与标准的同一部分中的另一个句子直接相矛盾的单词。不要选择与您个人首选使用该词有密切匹配的词,或者最常用的词。
答案 1 :(得分:9)
C ++不允许大小为零的对象,因为每个对象必须具有唯一的内存地址。所以如果你有:
struct empty {};
// ...
empty myempty;
empty* ptr = &myempty;
然后ptr
必须指向唯一的内存地址。标准规定对象的最小大小为1个字节。类似地,允许大小为0的分配,并返回有效指针,即使不允许写入该指针(这适用于malloc(0)
,并且new empty
返回指向一个字节的指针,因为{{ 1}})。
如果我从sizeof(empty) == 1
得到这样的话:
empty
基类struct derived : public empty
{
int data;
}
中不再有任何占用一个字节的点,因为empty
会员所有derived
都有一个唯一的地址。在这种情况下,引用“基类子对象可以具有零大小”以允许编译器不使用data
的任何空间,例如empty
。正如标题所述,它只是一种优化,sizeof(derived) == 4
empty
部分占据零空间是完全合法的。
答案 2 :(得分:2)
C ++标准1.8.5规定: -
除非它是位域(9.6),否则最多 派生对象应具有非零值 尺寸并占据一个或多个 存储字节。 基类 子对象可能没有大小。一个 平凡可复制的对象或 标准布局类型(3.9)应 占用连续的存储字节。
因此,标准允许没有数据成员(并且没有虚拟)的基类与具有不同类型的另一个子对象共享相同的地址。您可以使用像...这样的空基类大小。
struct a{};
struct a1{};
struct b : public a, public a1{char c;};
int main()
{
std::cout << sizeof(b) << "\n";
std::cout << sizeof(b::a);
}
Which outputs (ignoring padding)...
1
1
now try:
struct a{};
struct b : public a {a ax;};
int main()
{
std::cout << sizeof(b) << "\n";
std::cout << sizeof(b::a);
}
and the output is ...
2
1
因为a的两个实例(作为基础和成员)必须具有不同的地址。
BTW :“b :: a”是说“a”的另一种方式。范围访问运算符的存在不会请求“类型为a的b的基类子对象”。 Verse 5.3.3/2
说: - 将sizeof应用于基类子对象时,结果是该对象类型的大小。