Access Private Member Using Template Trick

access private member using template trick

You are not calling get from a! Actually what get return is a class pointer to a member inside A and type of it is int A::* so you need an instance of A to access that value.

For example let me play a little with your code:

struct A {
A(int a):a(a) { }
int b;
private:
int a;
};
void test() {
auto p = &A::b;
std::cout << a.*p << std::endl;
}

Did I call p from inside a? a does not have p, this is exactly what happened in your code, get function return &A::a and you use a to read its value! that's all, nothing is wrong and I think it will be compiled in all compilers.

One other question here is: Why C++ allow declaring template using private member of A. C++ standard say:

14.7.2p8 The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template
arguments and names used in the function declarator (including
parameter types, return types and exception specifications) may be
private types or objects which would normally not be accessible and
the template may be a member template or member function which would
not normally be accessible.]

But if you try to instantiate or even typedef specified template then you get an error.
Let's modify your example slightly:

struct A {
private:
int a;
friend void f();
};

// Explicit instantiation - OK, no access checks
template struct Rob<A_f, &A::a>;

// Try to use the type in some way - get an error.
struct Rob<A_f, &A::a> r; // error
typedef struct Rob<A_f, &A::a> R; // error
void g(struct Rob<A_f, &A::a>); // error

// However, it's Ok inside a friend function.
void f() {
Rob<A_f, &A::a> r; // OK
typedef Rob<A_f, &A::a> R; // OK
}

C++::Access to more than one private members using templates trick

This is because typename Tag::type is both int A::*, so both instantiation define the same function.

To fix this, you'll need to change the example a bit so it uses multiple tag types:

#include <iostream>

template<typename Tag, typename Tag::type M>
struct Rob {
// Here we receive tag directly
friend typename Tag::type get(Tag) {
return M;
}
};

// use
struct A {
A(int a) :a(a) { }
private:
int a;
int b;
};

// tag used to access A::a
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};

struct A_af : TagBase<A_af, int A::*> { };
struct A_bf : TagBase<A_bf, int A::*> { };

template struct Rob<A_af, &A::a>;
template struct Rob<A_bf, &A::b>;

int main() {
A a(42);
std::cout << "proof: " << a.*get(A_bf()) << a.*get(A_af()) << std::endl;
}

Detect existence of private member

There is indeed a way for non-final non-union class types:

namespace detail {
struct P {typedef int member;};
template <typename U>
struct test_for_member : U, P
{
template <typename T=test_for_member, typename = typename T::member>
static std::false_type test(int);
static std::true_type test(float);
};
}
template <typename T>
using test_for_member =
std::integral_constant<bool, decltype(detail::test_for_member<T>::test(0)){}>;

Demo. The trick is to check whether lookup into different base classes will yield an ambiguity. [class.member.lookup]/2:

Member name lookup determines the meaning of a name (id-expression)
in a class scope (3.3.7). Name lookup can result in an ambiguity, in
which case the program is ill-formed. […] Name lookup takes place
before access control (3.4, Clause 11).

Note that GCCs lookup is broken insofar as it ignores non-type names for lookup in typename-specifiers.

Can I access private members from outside the class without using friends?

If the class contains any template member functions you can specialize that member function to suit your needs. Even if the original developer didn't think of it.

safe.h

class safe
{
int money;

public:
safe()
: money(1000000)
{
}

template <typename T>
void backdoor()
{
// Do some stuff.
}
};

main.cpp:

#include <safe.h>
#include <iostream>

class key;

template <>
void safe::backdoor<key>()
{
// My specialization.
money -= 100000;
std::cout << money << "\n";
}

int main()
{
safe s;
s.backdoor<key>();
s.backdoor<key>();
}

Output:

900000
800000

How to access private data members outside the class without making friends?

You can't. That member is private, it's not visible outside the class. That's the whole point of the public/protected/private modifiers.

(You could probably use dirty pointer tricks though, but my guess is that you'd enter undefined behavior territory pretty fast.)



Related Topics



Leave a reply



Submit