从一个博客帖子访问私有成员:更安全的污秽由约翰内斯·绍布- litb:
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M;
}
};
// use
struct A {
A(int a):a(a) { }
private:
int a;
};
// tag used to access A::a
struct A_f {
typedef int A::*type;
friend type get(A_f);
};
template struct Rob<A_f, &A::a>;
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如何get
从a
对象调用函数,因为它没有在里面定义class A
?
编辑:
我不明白为什么get必须有Tag作为参数而不是 a.*get<A_f>()
=> ok它是由于ADL机制
你不打电话get
来a
!实际上,返回的是一个指向内部成员的类指针A
,它的类型是int A::*
你需要一个A
访问该值的实例.
例如,让我玩你的代码:
struct A {
A(int a):a(a) { }
int b;
private:
int a;
};
void test() {
auto p = &A::b;
std::cout << a.*p << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我是p
从里面打来的a
吗?a
没有p
,这正是你的代码中发生的事情,get
函数返回&A::a
,你用它a
来读取它的值!这就是全部,没有什么是错的,我认为它将在所有编译器中编译.
另一个问题是:为什么C++允许使用私有成员声明模板A
.C++标准说:
14.7.2p8通常的访问检查规则不适用于用于指定显式实例化的名称.[注意:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是通常不可访问的私有类型或对象,模板可能是成员模板或成员函数通常无法访问.]
但是,如果您尝试实例化甚至typedef
指定模板,则会出现错误.让我们稍微修改你的例子:
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
}
Run Code Online (Sandbox Code Playgroud)