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
How to Use a Custom Type as Key for a Map in C++
Same Class Name in Different C++ Files
Add Library to Visual Studio 2008 C++ Project
Can Std::Vector Emplace_Back Copy Construct from an Element of the Vector Itself
Use of Typename Keyword with Typedef and New
What Is the Size of an Enum Type Data in C++
C++ Trying to Swap Values in a Vector
Switch "Transfer of Control Bypasses Initialization Of:" When Calling a Function
Is There a Standard Way of Moving a Range into a Vector
Why Was Pair Range Access Removed from C++11
Why Does the C++ Standard Algorithm "Count" Return a Difference_Type Instead of Size_T
Memory Allocation Profiling in C++
Deprecated Throw-List in C++11
How Are the _Cplusplus Directive Defined in Various Compilers
Problems Using Member Function as Custom Deleter with Std::Shared_Ptr
What Could C/C++ "Lose" If They Defined a Standard Abi