I recently ran into this question while I was working on a project, and it confused me a bit. So I decided to write a test program to get a definitive answer:
#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;
}
This program creates 3 objects. layer2 is created inside layer1, and layer3 is created inside layer2. Then I call to get the addresses of layer1, layer2, and layer3, and just as was happening before, this is the output:
$ ./a.exe
0x28ac4f : layer 1's address
0x28ac4f : layer 2's address
0x28ac4f : layer 3's address
How can all three of these objects share the same spot in memory? What if I scaled this program to have 50 layers (objects)? Or 10,000? I’m not quite sure how this is possible. Can someone please put me in my place and explain what’s going on here?
Edit: Perhaps it’s because I instantiated the objects in private rather than in the objects’ constructors? Baah I don’t know.
The most definitive answer is that given by the C++ standard:
That is, if an object is a subject of another, they may have the same address.
In C++11, a standard-layout struct (despite its name, that can be a
classtoo) object’s first member is guaranteed to have the same address as the object itself:Since your classes are all standard-layout, the behaviour you’ve observed is guaranteed by C++11.
In C++03, the rule is similar, but applies to POD-struct types, rather than standard-layout struct types. Your classes, however, are not POD-struct types because they have user-defined destructors. So the behaviour you see here is not guaranteed by C++03.
So why can this occur? Well all a class really is is a way to group some data together and provide operations on that data. Consider a class that just contains an
intlike so:All this class is made up of is that
int. When you create an object of typeA, all you’re really doing is allocating enough space for its innards and initialising them (or in this case, not initialising them). Let’s say we create two instances ofA:What do we have in memory? You could imagine that it looks like this:
If we know that
Ajust contains anint– that is, anAobject is really nothing more than anint(except for maybe some padding) – then we know that the memory actually looks something like this if we break it down a bit more:You can see here that the
Aandintwould both have the same address because theintis a subobject of the objects of typeA. IfAcontained both anintand achar, it might look something like this:We know that
charwill have a higher address than theintbecause, once again, the standard says so:Note that a subobject does not necessarily share its address with the object its contained within, even if it’s the first one. It’s entirely up to the compiler.