我偶然发现了这个问题,其答案使用了一个奇怪的结构:
typedef std::queue<int> Q;
typedef Q::container_type C;
C & get (Q &q)
{
struct hack : private Q {
static C & get (Q &q) {
return q.*&hack::c;
}
};
return hack::get(q);
}
Run Code Online (Sandbox Code Playgroud)
我通常遵循它q可以访问c由get函数引用的自己的成员.但是,我无法清楚地解释它.究竟发生了什么.*&,为什么允许?
Yak*_*ont 27
typedef std::queue<int> Q;
Run Code Online (Sandbox Code Playgroud)
Q是一个queue改编的容器.
typedef Q::container_type C;
Run Code Online (Sandbox Code Playgroud)
C是 - 的基础容器Q- 这是一个deque<int>.
C & get (Q &q) {
Run Code Online (Sandbox Code Playgroud)
get拿a queue并返回a deque.事实上,它返回deque的queue包裹:通过常规手段,这是不可能的.
struct hack : private Q {
Run Code Online (Sandbox Code Playgroud)
hack是函数的本地类型.它继承Q并且只有一个静态成员函数.从它的名字,你可能会怀疑它是一个黑客.你是对的.
没有hack被实例化.
static C & get (Q &q) {
Run Code Online (Sandbox Code Playgroud)
hack::get与get自己具有相同的签名.事实上,我们将所有工作委托get给这个方法.
return q.*&hack::c;
Run Code Online (Sandbox Code Playgroud)
这条线需要分解.我将在更多行中做到:
using mem_ptr_t = C Q::*; // aka typedef C Q::*mem_ptr_t;
mem_ptr_t c_mem_ptr = &hack::c;
C& ret = q.*c_mem_ptr;
return ret;
Run Code Online (Sandbox Code Playgroud)
第一行定义了一个构件指针的类型类型的字段C内的Q.C++ 11和C++ 03命名这种类型的方式都很难看.
第二行得到一个构件指针字段c在Q.它是通过C++类型系统中的漏洞实现的. &hack::c逻辑上是类型C hack::*- 指向C类类中的类型成员的指针hack.事实上,这就是为什么我们可以在一个static成员中访问它hack.但c问题实际上在于Q,所以C++中表达式的实际类型是C Q::*:指向成员变量的指针Q.
你不能直接获得这个成员指针hack- &Q::c是非法的,但&hack::c不是.
你可以把成员指针为"输入偏移"成另一种类型的:&hack::c是的"偏移" c内Q有知道它是类型在一起C.现在,这是不是真的-这是一些不透明的值,它告诉编译器如何获得c从Q-但它有助于想想这种方式(它可以实现在简单的情况下,这种方式).
然后,我们一起用这个成员指针与Q&获得c出的Q.获取成员指针受受保护约束:使用它不是!我们这样做的方法是使用operator .*,它是成员解引用操作符,您可以在其中传递成员函数指针或成员,在左侧传递类实例.
instance .* member_ptr是一个表达式,用于查找成员"指向" member_ptr的内容instance.在原始代码中,所有内容都在一行中完成:
instance .* &class_name::member_name
Run Code Online (Sandbox Code Playgroud)
所以看起来有一个操作员.*&.
}
};
Run Code Online (Sandbox Code Playgroud)
然后我们关闭静态方法和hack类,并且:
return hack::get(q);
}
Run Code Online (Sandbox Code Playgroud)
叫它.这种技术可以访问protected状态:没有它,protected只能在同一实例的子类中访问成员.使用它,我们可以访问任何实例的protected成员,而不会违反任何标准.
这是一个黑客,正如命名法所指出的那样.
.*在左侧获取一个对象,在右侧获取一个成员指针,并解析给定对象的指向成员.&当然是参考运营商; &Class::Member返回一个成员指针,它本身不能被解除引用但可以与.*和->*运算符一起使用(后者是所有C++运算符中最古怪的).因此,obj .* &Class::Member具有完全相同的效果的obj.Member.
使用这个更复杂的版本的原因归结为保护语义的漏洞; 基本上,它允许访问protected基类对象的成员,即使该对象与执行此脏黑客的类的类型不同.
就个人而言,我觉得这个伎俩太聪明了一半.我通常会*编写以下代码:
struct hack : private Q {
static C & get (Q &q) {
return static_cast<hack &>(q).c;
}
};
Run Code Online (Sandbox Code Playgroud)
这在技术上稍微不那么安全,但不会掩盖正在发生的事情.
.*嗯,通常我会避免写这样的东西.但我今天早些时候确实做到了这一点,所以我不能真的扔石头.
| 归档时间: |
|
| 查看次数: |
1268 次 |
| 最近记录: |