我偶然发现this question,其答案使用了一个奇怪的结构:
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);
}
我通常认为q
可以访问由c
函数引用的自己的get
成员。但是,我无法清楚地解释它。 .*&
究竟发生了什么,为什么允许这样做?
答案 0 :(得分:26)
typedef std::queue<int> Q;
Q
是queue
改编的容器。
typedef Q::container_type C;
C
是Q
的基础容器 - deque<int>
。
C & get (Q &q) {
get
需要queue
并返回deque
。实际上它会返回deque
包裹的queue
:通过传统方式,这是不可能的。
struct hack : private Q {
hack
是函数的本地类型。它继承自Q
并且只有一个静态成员函数。从它的名字,你可能会怀疑它是一个黑客。你是对的。
没有hack
被实例化。
static C & get (Q &q) {
hack::get
与get
本身具有相同的签名。事实上,我们将get
的所有工作委托给此方法。
return q.*&hack::c;
这条线需要分解。我将在更多行中完成:
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;
第一行定义指向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
的“偏移量”,同时知道它的类型为{{1} }}。现在这不是真的 - 它是一些不透明的值告诉编译器如何从C
获取c
- 但它有助于以这种方式思考它(并且可以实现在简单的情况下)。
然后我们将此成员指针与Q
一起使用,以从Q&
中获取c
。获取成员指针受受保护约束:使用它不是!我们这样做的方法是使用运算符Q
,它是成员解引用运算符,您可以在右侧传递成员函数指针或成员,在左侧传递类实例。 / p>
.*
是一个表达式,可在instance .* member_ptr
中找到member_ptr
所指的成员“指向”。在原始代码中,所有内容都在一行中完成:
instance
所以看起来有一个运算符instance .* &class_name::member_name
。
.*&
然后我们关闭静态方法和 }
};
类,并且:
hack
打电话给它。此技术可以访问 return hack::get(q);
}
状态:没有它,protected
成员只能在同一实例的子类中访问。使用此功能,我们可以访问任何实例的protected
个成员,而不会违反任何标准。
答案 1 :(得分:8)
这是一个黑客,正如命名法所示。
.*
在左侧获取一个对象,在右侧获取一个成员指针,并解析给定对象的指向成员。当然,&
是引用运算符; &Class::Member
返回一个成员指针,它本身不能被解除引用但可以与.*
和->*
运算符一起使用(后者是所有C ++运算符中最古怪的运算符)。因此obj .* &Class::Member
与obj.Member
具有完全相同的效果。
使用这个更复杂的版本的原因归结为保护语义的漏洞;基本上,它允许访问基类对象的protected
成员,即使该对象与执行此脏攻击的类的类型不同。
就个人而言,我认为诀窍太巧妙了一半。我通常会把这样的代码写成:
struct hack : private Q {
static C & get (Q &q) {
return static_cast<hack &>(q).c;
}
};
这在技术上稍微不那么安全,但不会掩盖正在发生的事情。
。*嗯,通常我会避免写这样的东西。但是我今天早些时候做到了这一点,所以我不能扔石头。