C ++ Multiple Inheritance - a compiler modifying my pointers

If I run the following code, I get different addresses. Why?

class Base1 { int x; }; class Base2 { int y; }; class Derived : public Base1, public Base2 { }; union U { Base2* b; Derived* d; U(Base2* b2) : b(b) {} }; int main() { Derived* d = new Derived; cout << d << "\n"; cout << U(d).d << "\n"; return 0; } 

Even more fun, if you repeatedly enter and exit the union, the address continues to increase by 4, like this

 int main() { Derived* d = new Derived; cout << d << "\n"; d = U(d).d; cout << d << "\n"; d = U(d).d; cout << d << "\n"; return 0; } 

If the union changes in this way, then the problem disappears

 union U { void* v; Base2* b; Derived* d; U(void* v) : v(v) {} }; 

In addition, if the base class becomes empty, the problem disappears. Is this a compiler error? I want him to leave my pointers alone.

+4
source share
2 answers

If I run the following code, I get different addresses. Why?

Because the Base2 sub-object of the Base2 object is not at the beginning of the Derived object. Thus, the addresses are different. When the compiler performs an implicit conversion from Derived* to Base2* , it needs to configure the address.

Given the definitions of the Base1 and Base2 , both sub-objects of the Derived class cannot be on the starting address of the Derived object - there is no place in this address for both subtexts -Objects.

Let's say you have this code:

 Derived* d = new Derived; Base1* pb1 = d; Base2* pb2 = d; 

How would it be possible for pb1 and pb2 point to the same address? pb1 must point to an element of Base1::x , and pb2 must point to an element of Base2::y (and these elements must be different).

Even more fun, if you repeatedly enter and exit the union, the address continues to increase by 4

Since you read the union d member after writing the b member, which is undefined (you essentially do something like reinterpret_cast<Derived*>() on Base2* ).

I want him to leave my pointers alone.

Not if you want a Base2* pointer. Multiple inheritance makes things more complicated - so many people suggest avoiding this if absolutely necessary.

+3
source

Union constructor never initializes member d

The union constructor has an error, where instead of initializing element b with parameter b2, it initializes b with itself

 // b(b) should probably be b(b2) U(Base2* b2) : b(b) {} 

When your first example of the main function tries to create an instance of U and the print element d, it actually prints the value undefined, since the element d is not initialized and is not guaranteed to be available.

 // U(d) doesn't construct member d, so .d returns an undefined value cout << U(d).d << "\n"; 

Regarding the second example of basic functions

 // d is set to a newly constructed instance of Derived Derived* d = new Derived; // current address of d is printed cout << d << "\n"; // a new instance of U is constructed. The address of member d will be in close // proximity to the newly initialized U instance, and is what will be printed d = U(d).d; cout << d << "\n"; // yet another new instance of U is constructed, and again, the address of member // d will be in close proximity to the newly initialized U instance, and is //what will be printed d = U(d).d; cout << d << "\n"; 
+2
source

Source: https://habr.com/ru/post/1440916/


All Articles