If I run the following code, I get different addresses printed. 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 is if you repeatedly go in and out of the union the address keeps incrementing 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 is modified like this, then the problem goes away
union U {
void* v;
Base2* b;
Derived* d;
U(void* v) : v(v) {}
};
Also, if either base class is made empty, the problem goes away.
Is this a compiler bug? I want it to leave my pointers the hell alone.
Because the
Base2sub-object of theDerivedobject isn’t at the start of theDerivedobject. So the addresses are different. When the compiler performs an implicit cast from aDerived*to aBase2*, it needs to adjust the address.Given the definitions of the
Base1andBase2classes, both sub-objects of theDerivedclass cannot possibly be at the starting address of aDerivedobject – there’s no room at that address for both sub-objects.Say you had this code:
How would it be possible for
pb1andpb2to point to the same address?pb1has to point to aBase1::xitem, andpb2has to point to aBase2::yitem (and those items have to be distinct).Because you’re reading from the union’s
dmember after writing thebmember, which is undefined behavior (you’re essentially performing something like areinterpret_cast<Derived*>()on aBase2*).Not if you want a
Base2*pointer. Multiple inheritance makes things more complex – that’s why many people suggest avoiding it unless absolutely necessary.