Consider these classes that will act as base classes:
struct Base1 {
int b1;
void print_Base1_addr() const { std::cout << this << '\n'; }
};
struct Base2 {
int b2;
void print_Base2_addr() const { std::cout << this << '\n'; }
};
If Derived
inherits from Base1
and Base2
:
struct Derived: Base1, Base2 {
int i;
void print_addr() const { std::cout << this << '\n'; }
};
Then this code prints the same address for this
in Derived
and Base1
but not in Base2
:
Derived d{};
d.print_addr();
d.print_Base1_addr();
d.print_Base2_addr();
I don't understand why this
in Derived
has the same address as in Base1
. These aren't empty classes as they all contain a data member (the addresses of the data members b1
and i
differ). It is as if Base1
overlaps on the Derived
.
What I am overlooking?
I don't understand why this in Derived has the same address as in Base1.
Why not? The derived object contains the base class subobjects. Sub objects can have the same address as the container object.
The layout in memory probably looks something like this:
mem addr | 0123456789ab # relative to the address of Derived object
Base1 | 1111 # 1 denotes address occupied by Derived::Base1
Base2 | 2222 # 2 denotes address occupied by Derived::Base2
i | iiii # i denotes address occupied by Derived::i
Derived | DDDDDDDDDDDD # D denotes address occupied by Derived
-------------------------
all subobj | 11112222iiii
Notice how the beginning of both 1 and D overlap at the address 0.
It is as if Base1 overlaps on the Derived.
That is exactly how subobjects behave. Just like elements of array overlap the entire array, members of a class overlap the class, so too the base class sub objects overlap the memory of the derived class.