空基类优化

时间:2010-05-13 12:09:56

标签: c++

C ++标准中的两个引号,§1.8:

  

对象是存储区域。

     

基类子对象的大小可能为零。

我不认为存储区域的大小为零。这意味着某些基类子对象实际上不是对象。这些陈述如何共存?

3 个答案:

答案 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应用于基类子对象时,结果是该对象类型的大小