派生类比基类大,即使它由引用变量组成

时间:2013-04-17 13:52:37

标签: c++

从我到目前为止所读到的,似乎参考变量根本不应该占用任何内存。相反,它们被视为它们引用的完全相同的变量,但具有另一个名称。

但是,当我运行以下代码时,似乎并非总是如此:

#include <cstdio>
struct A
{
    int m[3];
};
struct B: A
{
    B():x(m[0]), y(m[1]), z(m[2]){}
    int& x;
    int& y;
    int& z;
};
int main(){
    printf("%u, %u\n", sizeof(A), sizeof(B));
    return 0;
}

输出:

12, 40

为什么B比A大得多?

我还有其他方式可以访问,例如B.m [0]和B.x?

3 个答案:

答案 0 :(得分:7)

  

从我到目前为止所读到的,似乎参考变量根本不应该占用任何内存。

你应该进一步阅读;) 说真的,引用并不神奇。所以在现实世界中,对象必须以某种方式存储关于引用绑定到哪个对象的信息。因此,从概念上讲,引用没有大小,它实际上非常像指针,通常编译器只使用指针。在编译时,编译器强制执行与指针(非空,不可重新分配,无需取消引用)的行为。

所以你看到的基本上是A plus padding的大小加上三个指针的大小。我猜您使用的是64位系统sizeof(int)为4且sizeof(void*)为8:

 12 bytes for the A subobject (4 for each int)
+ 4 bytes padding (to get to a multiple of 8 bytes)
+24 bytes for the 3 references/pointers in B (8 for each one)
--------------
 40 bytes total

对于您的其他问题,如果对象b类型为B,您可以直接访问b.m[0],因为它在A中已公开并已公开继承。在没有您遇到的参考开销的情况下给它另一个名称是不可能的。

答案 1 :(得分:4)

你在解释错误的事情。一个 reference that is used purely locally can - and often is - eliminated by the optimizer 。请注意,我们仍然需要在其生命周期中将其存储在某个地方(例如寄存器中)。

编译器无法像局部变量一样容易地预测对象的生命周期,因此,成员引用实际上不能被替换和丢弃:必须将指针(4字节或8字节)保存到在对象生命周期内保持成员一致的实际内容。

答案 2 :(得分:2)

引用就像一个指针,它不能为空,永远不能“重新安置”(指向不同于它最初指向的东西)。因此,我们可能期望引用占用与指针相同的空间量(尽管这不能保证)。因此三个整数,4个字节用于对齐,然后三个8字节指针将是40个字节,使您的示例完全合理。

您可以使B.x()之类的方法返回值而不占用更多空间。但是由于C ++缺少“属性”,你不能让B.x返回不占空间的东西(即你不能制作看起来像成员变量访问但行为类似于方法调用的东西)。