I have the following class:
class BritneySpears
{
public:
int getValue() { return m_value; };
private:
int m_value;
};
Which is an external library (that I can't change). I obviously can't change the value of m_value
, only read it. Even deriving from BritneySpears
won't work.
What if I define the following class:
class AshtonKutcher
{
public:
int getValue() { return m_value; };
public:
int m_value;
};
And then do:
BritneySpears b;
// Here comes the ugly hack
AshtonKutcher* a = reinterpret_cast<AshtonKutcher*>(&b);
a->m_value = 17;
// Print out the value
std::cout << b.getValue() << std::endl;
I know this is bad practice. But just out of curiosity: is this guaranteed to work? Is it defined behaviour?
Bonus question: Have you ever had to use such an ugly hack?
This is undefined behaviour. The members within each access-qualifier section are guaranteed to be laid out in the order they appear, but there is no such guarantee between acccess qualifiers. For instance, if the compiler chooses to place all private members before all public members, the above two classes will have a different layout.
Edit: Revisiting this old answer, I realized that I missed a rather obvious point: the struct definitions have exactly one data member each. The order of member functions is irrelevant, since they don't contribute to the class's layout. You might well find that both data members are guaranteed to be in the same place, though I don't know the standard well enough to say for sure.
But! You cannot dereference the result of
reinterpret_cast
ing between unrelated types. It's still UB. At least, that's my reading of http://en.cppreference.com/w/cpp/language/reinterpret_cast, which is a gnarly read indeed.This is undefined behavior, for the reasons Marcelo pointed out. But sometimes you need to resort to such things when integrating external code you can't modify. A simpler way to do it (and equally undefined behavior) is:
You might not be able to modify the library for
BritneySpears
, but you should be able to modify the .h header file. If so, you can makeAshtonKutcher
a friend ofBritneySpears
:I can't really condone this trick, and I don't think I've ever tried it myself, but it should be legal well-defined C++.
There is an issue with your code, underlined by the answers. The problem comes from ordering the values.
However you were almost there:
Now, you have the exact same layout because you have the same attributes, declared in the same order, and with the same access rights... and neither object has a virtual table.
The trick is thus not to change the access level, but to add a method :)
Unless, of course, I missed something.
Did I precise it was a maintenance nightmare ?
Use of reinterpret_cast should usually be avoided and it's not guaranteed to give portable results.
Also, why do you want to change the private member? You could just wrap the original class in a new one (prefer composition over inheritance) and handle the getValue method as you wish.
@Marcelo has it right: the order of members is undefined across different access levels.
But consider the following code; here,
AshtonKutcher
has exactly the same layout asBritneySpears
:I believe that this may actually be valid C++.