Why does static_cast provide different memory locations for the same object?

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 address is at : " <<&GC<<endl;
    std::cout << "Child address is at : " <<static_cast<Child*>(&GC)<<endl;
    std::cout << "Parent address is at : " <<static_cast<Parent*>(&GC)<<endl;

}

      

output:

GrandChild address is at : 0077F6F8
Child address is at : 0077F6FC
Parent address is at : 0077F6F8

      

Why after static_cast memory cells have inconsistencies as above?

+3


source to share


5 answers


GrandChild

comes from Parent

and Child

. Thus, an object GrandChild

in memory consists of an object Parent

object Child

in its memory.

&GC

by itself returns the address of the GrandChild

object GrandChild

as a whole

static_cast<Parent*>(&GC)

returns the starting address of the Parent

part inside the object GrandChild

.



static_cast<Child*>(&GC)

returns the starting address of the Child

part inside the GrandChild

object.

In your case Grandchild

, inherits from first Parent

, so the Parent

part is aligned at the beginning of GrandChild

memory GrandChild

. Then Child

part follows Parent

part. Here is an illustration to show that:

structure

+12


source


&GC

is the address of the object GrandChild

GC

. static_cast<Child*>(&GC)

is the address of the subject Child

GC

. And static_cast<Parent*>(&GC)

- this is the address of the subject Parent

GC

.



In your specific implementation, it seems that the object GrandChild

starts with a subobject Parent

and then the subobject Child

comes after, so the subobject's address is the Parent

same as the full object's GrandChild

address, but the first byte subobject is Child

not the first byte of the full object GrandChild

, so its address is higher. However, you cannot rely on portable behavior; different implementations can allocate base class and member subobjects in different orders and do not even have to be compatible between different classes.

+5


source


In your example, this is predictable even though it's implementation defined (but developers are allowed to choose straight forward solutions for simple cases :-))

Here's a memory representation of your object (derived from addresses, not 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 from first Parent

, then from Child

. With this representation, it makes sense that the address Parent

will be the same as GrandChild

one, but for Child

"address, there will be 4 more.

Also note that GrandChild::a

do not Parent::a

...

+2


source


It looks like it depends on the sequence in which GrandChild is inherited from parent and child.

In the following sequence, I received

struct GrandChild : public Parent, public Child { int a, b, c; };

      

Output 1: GrandChilds address matches parent's

GrandChild address is at : 0x22fecc
Child address is at : 0x22fed0
Parent address is at : 0x22fecc

      

When changing the sequence in which GrandChild inherits from Child and Parent to

struct GrandChild :  public Child , public Parent { int a, b, c; };

      

Output 2: GrandChilds address is the same as Child's

GrandChild address is at : 0x22fecc
Child address is at : 0x22fecc
Parent address is at : 0x22fed0

      

0


source


The other answers here have worked great, but let me worry anyway.

First, the parent is not the parent, and the child is not the child ... of the parent; how it did not inherit from the parent. Both Parent and Child are legacy from GrandParent, which is not ... the grandparent!

Second, to answer your question, the effects you are observing are not really inconsistencies, but how C ++ implements polymorphism. (I don't think the other answers have made this clear).

PolyMorphism (poly = many, morphism = morphing into) is an object-oriented programming concept that allows one object to turn into many different objects at runtime. This allows the object to behave differently. For example, now it might be a dog, then a cat, and later a ghost.

How polymorphism is implemented in most object-oriented languages, C ++, Java, etc. Through pointer arithmetic (increment) and inheritance. It would be great if std :: string could transform to std :: vector, but since they do not share inheritance, this is not syntactically possible.

However, in the case of your parent class, it can become GrandParent or any other derived class. Likewise, GrandParent can turn into Parent or Child.

ANOTHER NAME OF POLYMORPHISM IS POLYMORPHIC CONVERSION !!!

Based on your question, it is important to understand that polymorphism is a type of C ++ conversion. The C ++ conversion is designed to be accurate and lossless. For example, you can convert int to char and vice versa. Data integrity is maintained! Likewise, if I convert from GrandParent to Child (which is what static_cast does); Your best bet is to set the object pointer to the Child address. If we convert to child and continue reading from GrandParent, we will read WRONG DATA. In your case, when you inherited first from Parent, we will end up reading the a and b values ​​stored in Parent.

Even worse, it becomes more obvious that such a treatment would be wrong. If we are converting to Child, and child has a special getString function, for example, if we call this function from the start address of the GrandChild, BOOM! We will definitely get a crash at runtime!

I hope you enjoyed this video and learned a thing or two. If you want more free videos, don't forget to subscribe. Thank.

0


source







All Articles