我有一个用 C++ 编写的静态库。我还获得了静态库中定义的类的头文件。
我可以访问在类声明中引入友元函数的静态库中定义的类的私有成员吗?
我有一个用 C++ 编写的静态库。我还获得了静态库中定义的类的头文件。
我可以访问在类声明中引入友元函数的静态库中定义的类的私有成员吗?
您的意思是要更改库附带的标头?不能保证在friend
那里添加声明会起作用。即使您的编译器说没问题,您也可能会弄乱链接部分。
此外,如果这些成员是private
,您就不能访问它们。
使用不同的标记序列在不同的翻译单元中定义相同的实体(这里是一个类)在技术上是未定义的行为。
无论您使用什么技术,只要它改变了组成它的标记序列,从标准的角度来看,它都是邪恶的(尽管可能在实践中起作用)。
Johannes发现了一种在尊重标准的同时做到这一点的方法。它基于这样一个事实,即使a
是 class 中的私有属性A
,&A::a
也可以在无法写入的上下文中编写A.a
(也许是标准中的疏忽?)。
核心方法:
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;
}
为简单起见扩展:
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};
struct A_f : TagBase<A_f, int A::*> { };
编辑:
这个技巧(有趣地)被标准明确允许
§14.7.2/12通常的访问检查规则不适用于用于指定显式实例化的名称。[...]