My code
class Parent { int a; };
class Child { int b; };
struct GrandChild : public Parent, public Child { int a, b, c; };
int main() {
GrandChild GC;
std::cout << "GrandChild's address is at : " <<&GC<<endl;
std::cout << "Child's address is at : " <<static_cast<Child*>(&GC)<<endl;
std::cout << "Parent's address is at : " <<static_cast<Parent*>(&GC)<<endl;
}
output:
GrandChild's address is at : 0077F6F8
Child's address is at : 0077F6FC
Parent's address is at : 0077F6F8
Why does after static_cast the memory locations have inconsistencies like above?
GrandChild derives from both Parent and Child. As such, a GrandChild object in memory consists of both a Parent object and a Child object within its memory.
&GC by itself returns the memory address of the GrandChild object as a whole
static_cast<Parent*>(&GC) returns the starting address of the Parent portion inside the GrandChild object.
static_cast<Child*>(&GC) returns the starting address of the Child portion inside the GrandChild object.
In your case, Grandchild derives from Parent first, so the Parent portion is aligned at the beginning of the GrandChild's memory block. Then the Child portion follows the Parent portion. Here is an illustration to show that:

&GC is the address of the GrandChild object GC. static_cast<Child*>(&GC) is the address of the Child subobject of GC. And static_cast<Parent*>(&GC) is the address of the Parent subobject of GC.
In your particular implementation, it appears that a GrandChild object starts with a Parent subobject and then the Child subobject comes after, so the Parent subobject's address is the same as the complete GrandChild object's address, but the Child subobject's first byte is not the first byte of the complete GrandChild object, so its address is higher. You cannot rely on this behaviour being portable, however; different implementations may allocate base class and member subobjects in different orders, and do not even need to be consistent between different classes.
In your example, it is predictable even if it is implementation defined (but implementers are allowed to choose straight solutions for simple cases :-) )
Here is the memory representation of your object (deduced from the addresses, not from the standard !):
Parent::a (int = 4 bytes)
Child::b (int = 4 bytes)
GrandChild::a
GrandChild::b
GrandChild::c
This is because of your declaration : GrandChild inherits first from Parent, next from Child. With that representation, it makes sense for Parent's address to be the same as GrandChild's one, and for Child'address to be 4 bigger.
Also note that GrandChild::a is not Parent::a...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With