关于c ++:Derived类比基类大,即使它由引用变量组成


Derived class is bigger than base class even though it consists of reference variables

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

但是,当我运行以下代码时,似乎情况并非总是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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
"
, sizeof(A), sizeof(B));
    return 0;
}

输出:

1
12, 40

为什么B比A大那么多?

是否有其他方法可以访问,例如,使用b.x访问b.m[0]?


From what I've read so far, it seems that reference variables are not supposed to take any memory at all.

你应该进一步阅读;)说真的,参考不是魔法。所以在现实世界中,对象必须存储关于引用绑定到什么对象的信息。因此,虽然从概念上讲引用没有大小,但实际上它非常类似于指针,通常编译器只使用指针。编译器在编译时强制执行与指针不同的行为(不为空、不可重新分配、不需要取消对它的引用)。

所以你看到的基本上是一个加上填充的大小加上三个指针的大小。我猜你在64位系统中,sizeof(int)是4,sizeof(void*)是8:

1
2
3
4
5
 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中是公开的,并且是公开继承的。在没有引用开销的情况下给它另一个名称是不可能的。


你把事情解释错了。一个纯粹在本地使用的引用可以——而且常常被优化器消除。请注意,在IT生命周期中,我们仍然需要将其存储在某个地方(如寄存器中)。

编译器不能像局部变量那样容易地预测对象的寿命,因此,成员引用实际上不能被替换和丢弃:必须持有指向实际内容的指针(4bytes或8bytes),以便在对象寿命期间保持成员的一致性。


引用就像一个指针,它不能为空,也不能"重新放置"(指的是它最初指向的以外的东西)。因此,我们可能期望引用采用与指针相同的空间量(尽管这不一定)。所以3个整数,4个字节用于对齐,那么3个8字节指针将是40个字节,这使得您的示例非常合理。

您可以使用像B.x()这样的方法返回一个值,而不占用更多的空间。但是,由于C++缺少"属性",所以不能使EDCOX1〔1〕返回不占用空间的东西(即,不能生成看起来像成员变量访问但行为类似方法调用的东西)。