Reputation: 25
I want to access private members without modifying the .h file. This is an example of a .h file
class X
{
private:
class A
{...};
vector<A> arr;
}
Q:How can I access X::arr ?
class X
{
private:
int a;
};
template<typename Tag, typename Tag::type Member>
struct XAccessor
{
friend typename Tag::type get(Tag)
{
return Member;
}
};
struct X_A
{
typedef int X::* type;
friend type get(X_A);
};;
template struct XAccessor<X_A, &X::a>;
...
auto x = new X;
x->*get(X_A())=11;
...
I found this approach online, but when I changed typedef int X::* type
to typedef vector<X::A> X::* type
, it gave me an error saying that X::A
is not accessible.
Upvotes: -1
Views: 220
Reputation: 39424
If you can steal the data member pointer, you can extract the type from it. Here is a solution that works with zero modifications to the original X
.
Say we have a class X
which we can't modify, containing a private data member of private type Hidden
. In your example, Hidden = std::vector<A>
.
class X
{
private:
struct Hidden {};
Hidden a;
};
We can create a function that returns the data member pointer X::*a
, without naming the type X::Hidden
:
// the following three declarations give us a data member pointer to X::a
auto steal();
template <auto Ptr>
struct Thief {
friend auto steal() {
return Ptr;
}
};
// explicit instantiation of specialization Thief<&X::a>
template struct Thief<&X::a>;
The reason why this works is that member access restrictions are disabled when explicitly instantiating templates, so Thief<&X::a>
will not fail to compile.
This is intentional design, because otherwise you would be unable to explicitly instantiate any templates involving non-public members.
Thief
defines a hidden friend steal()
, which returns the data member pointer, and acts as a "jailbreak" for encapsulation.
steal()
is just a free function, and doesn't contain &X::a
or X::Hidden
in any template parameters or function parameters, so nothing restricts our access to it.
We also create a type trait so we can extract the data type from this pointer:
// trait which lets us extract Hidden from a data member pointer
template <typename T>
struct member_type;
template <typename C, typename M>
struct member_type<M C::*> {
using type = M;
};
Finally, we are able to access both the private type X::Hidden
, and the private data member X::a
:
// X_Hidden = X::Hidden
using X_Hidden = member_type<decltype(steal())>::type;
// steal private data member at runtime
X_Hidden get_a(const X &x) {
X_Hidden X::*a = steal();
return x.*a;
}
See live demo on Compiler Explorer.
Upvotes: 8