其他对象中的对象是否真的共享同一个地址?

xcd*_*n05 5 c++ memory object

我最近在处理一个项目时遇到了这个问题,这让我有点困惑.所以我决定编写一个测试程序来获得明确的答案:

#include <iostream>

using namespace std;

class layer3{
public:
    layer3(){}
    ~layer3(){}     
private:

};


class layer2{
public:
    layer2(){}
    ~layer2(){}

    layer3* GetBAddress(){return &b;}
private:
    layer3 b;
};


class layer1{
public:
    layer1(){}
    ~layer1(){}

    //returns the address of a, which is a 'layer2' object
    layer2* GetaAddress(){return &a;}
    //returns the address of b, which is is a layer 3 object
    layer3* GetDeepBAddress(){return a.GetBAddress();}
private:
    layer2 a;

};

int main(){

    layer1 t;
    cout << &t << "  : layer 1's address" << endl;
    cout << t.GetaAddress() <<  "  : layer 2's address" <<endl;
    cout << t.GetDeepTLAddress() <<  "  : layer 3's address" <<endl;

}
Run Code Online (Sandbox Code Playgroud)

该程序创建3个对象.layer2在layer1中创建,layer3在layer2中创建.然后我调用获取layer1,layer2和layer3的地址,就像之前发生的那样,这是输出:

$ ./a.exe
0x28ac4f  : layer 1's address
0x28ac4f  : layer 2's address
0x28ac4f  : layer 3's address
Run Code Online (Sandbox Code Playgroud)

这三个对象如何在内存中共享相同的位置?如果我将此程序缩放为50层(对象)怎么办?还是10,000?我不太确定这是怎么回事.有人可以把我放在我的位置并解释这里发生了什么?

编辑:也许是因为我在私有而不是在对象的构造函数中实例化对象?巴哈,我不知道.

Jos*_*eld 12

最明确的答案是C++标准给出的:

如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址; 否则,他们应有不同的地址.

也就是说,如果一个对象是另一个对象的主题,它们可能具有相同的地址.

在C++ 11中,标准布局结构(尽管它的名称,也可以是class)对象的第一个成员保证与对象本身具有相同的地址:

指向标准布局结构对象的指针(适当地使用a转换)reinterpret_cast指向其初始成员(或者如果该成员是位字段,则指向它所驻留的单元),反之亦然.

由于您的类都是标准布局,因此C++ 11保证您观察到的行为.

在C++ 03中,规则类似,但适用于POD结构类型,而不是标准布局结构类型.但是,您的类不是POD结构类型,因为它们具有用户定义的析构函数.因此,C++ 03 无法保证您在此处看到的行为.

那为什么会发生这种情况?实际上,所有类都是将一些数据组合在一起并提供对该数据的操作的方法.考虑一个只包含int类似的类:

class A
{
  int x;
};
Run Code Online (Sandbox Code Playgroud)

所有这一课都是由这个组成的int.当你创建一个类型的对象时A,你所做的只是为它的内部分配足够的空间并初始化它们(或者在这种情况下,不是初始化它们).假设我们创建两个实例A:

A a1;
A a2;
Run Code Online (Sandbox Code Playgroud)

我们在记忆中有什么?你可以想象它看起来像这样:

   a1     a2
?????????????????
?  A   ?  A   ?
?????????????????
Memory ------->
Run Code Online (Sandbox Code Playgroud)

如果我们知道A只包含一个int- 也就是说,一个A对象实际上只是一个int(除了可能是一些填充) - 那么我们知道如果我们将它分解得更多,那么内存实际上看起来像这样:

   a1     a2
?????????????????
? int  ? int  ?
?????????????????
Memory ------->
Run Code Online (Sandbox Code Playgroud)

你可以在这里看到,A并且int都将具有相同的地址,因为它int是类型对象的子对象A.如果A包含a int和a char,它可能看起来像这样:

       a1            a2
???????????????????????????????
? int  ? char ? int  ? char ?
???????????????????????????????
Memory ------->
Run Code Online (Sandbox Code Playgroud)

我们知道char会有比地址更高的地址int,标准也是这样说的:

分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址.

请注意,子对象不一定与其包含的对象共享其地址,即使它是第一个.这完全取决于编译器.