Despite your classes being layout compatible (see below), your code exhibits undefined behavior due to the fact that such pointer casts are prohibited by the C++ strict aliasing rules1.
But: replacing the casts with a union
makes the code standard-compliant; this is actually guaranteed to work in C++11:
#include <iostream>
using namespace std;
class Point {
private:
int x;
int y;
public:
Point(int x, int y) {
this->x = x;
this->y = y;
}
void Print() {
cout << "(" << x << ", " << y << ")" << endl;
}
};
struct PointHack {
int x;
int y;
};
union pu
{
Point p;
PointHack ph;
pu(int x, int y) : p(x, y) {}
};
int main() {
pu u(4,5);
u.p.Print();
u.ph.x=1;
u.ph.y=2;
u.p.Print();
return 0;
}
This comes from the fact that Point
and PointHack
are standard-layout classes2 (C++11, §9 ¶7), and share a "common initial subsequence" (§9.2, ¶20); as such, if they both are stored in the same union (here pu
) it's permitted to "inspect the common initial part of any of them"3.
Still, this answer is mostly an exercise of style; don't exploit such tricks unless you are really forced to. C++ provides better means to access private members if necessary without brutally breaking the encapsulation - you have getters/setters, protected inheritance, friend classes, ... And in general, if you access private class members in ways not intended by your target class, you are potentially violating the assumptions of that class about how its data is modified, which can lead to erratic behavior of the code of its methods.
Notes:
- In C++ you can't have two pointers of unrelated types pointing to the same object; this restriction is mostly used to help optimizers with assumptions about aliasing.
- Notice that the requirements for this are quite stringent; typically most classes that aren't basically C structs don't qualify for this. Even having different access qualifiers can break the magic.
- The idea is that assigning to
ph
makes it the "active object" of the union
, and then p.Print()
is the one "inspecting" the "inactive" object.