.*& 运算符的作用是什么?
What does the .*& operator do?
我偶然发现了 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
函数引用。但是,我无法清楚地解释它。 .*&
到底发生了什么,为什么允许这样做?
正如命名法所示,这是一个 hack。
.*
在左侧取一个对象,在右侧取一个成员指针,并解析给定对象的指向成员。 &
当然是引用运算符; &Class::Member
returns 一个成员指针,它本身不能被取消引用,但可以与 .*
和 ->*
运算符一起使用(后者是所有 C++ 运算符中最古怪的) .所以 obj .* &Class::Member
与 obj.Member
具有完全相同的 效果 。
使用这个更复杂版本的原因归结为保护语义中的漏洞;基本上,它允许访问基础 class 对象的 protected
成员,即使该对象与执行此肮脏 hack 的 class 的类型不同。
个人觉得这把戏高明了一半。我通常*会写这样的代码:
struct hack : private Q {
static C & get (Q &q) {
return static_cast<hack &>(q).c;
}
};
这在技术上稍微不太安全,但不会掩盖正在发生的事情。
.* 好吧,通常我会完全避免写这样的东西。但我今天早些时候真的这样做了,所以我真的不能扔石头。
typedef std::queue<int> Q;
Q
是一个 queue
适配的容器。
typedef Q::container_type C;
C
是 Q
的底层容器——它是 deque<int>
.
C & get (Q &q) {
get
需要一个 queue
和 returns 一个 deque
。事实上,returns 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 对这种类型的命名方式都很丑陋。
第二行获取指向Q
中字段c
的成员指针。它通过 C++ 类型系统中的漏洞来实现这一点。 &hack::c
在逻辑上属于 C hack::*
类型——指向 hack
类型的 class 中的 C
类型成员的指针。事实上,这就是为什么我们可以在 hack
的 static
成员中访问它。但是问题中的c
实际上是在Q
中,所以C++中表达式的实际类型是C Q::*
:指向Q
.[=71的成员变量的指针=]
不能在hack
中直接获取这个成员指针——&Q::c
是非法的,但&hack::c
是非法的。
您可以将成员指针视为 'typed offsets' 到另一种类型:&hack::c
是 Q
中 c
的 "offset" 并且知道它是类型 C
。现在这不是真的——它是一些不透明的值告诉编译器如何从 Q
得到 c
——但它有助于以这种方式思考它(并且它可能被实现简单情况下的方式)。
然后我们使用这个成员指针和 Q&
从 Q
中得到 c
。获取成员指针受保护限制:使用它不是!我们的做法是使用运算符.*
,它是成员解引用运算符,你可以在右边传递成员函数指针或成员,以及class 实例在左边。
instance .* member_ptr
是在instance
中通过member_ptr
查找成员"pointed to" 的表达式。在原始代码中,所有内容都在一行中完成:
instance .* &class_name::member_name
所以看起来好像有一个运算符 .*&
。
}
};
然后我们关闭静态方法和hack
class,还有:
return hack::get(q);
}
调用它。这种技术可以访问 protected
状态:没有它,protected
成员只能在同一实例的子 class 中访问。使用它,我们可以访问 any 实例的 protected
成员,而不会违反任何标准。
我偶然发现了 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
函数引用。但是,我无法清楚地解释它。 .*&
到底发生了什么,为什么允许这样做?
正如命名法所示,这是一个 hack。
.*
在左侧取一个对象,在右侧取一个成员指针,并解析给定对象的指向成员。 &
当然是引用运算符; &Class::Member
returns 一个成员指针,它本身不能被取消引用,但可以与 .*
和 ->*
运算符一起使用(后者是所有 C++ 运算符中最古怪的) .所以 obj .* &Class::Member
与 obj.Member
具有完全相同的 效果 。
使用这个更复杂版本的原因归结为保护语义中的漏洞;基本上,它允许访问基础 class 对象的 protected
成员,即使该对象与执行此肮脏 hack 的 class 的类型不同。
个人觉得这把戏高明了一半。我通常*会写这样的代码:
struct hack : private Q {
static C & get (Q &q) {
return static_cast<hack &>(q).c;
}
};
这在技术上稍微不太安全,但不会掩盖正在发生的事情。
.* 好吧,通常我会完全避免写这样的东西。但我今天早些时候真的这样做了,所以我真的不能扔石头。
typedef std::queue<int> Q;
Q
是一个 queue
适配的容器。
typedef Q::container_type C;
C
是 Q
的底层容器——它是 deque<int>
.
C & get (Q &q) {
get
需要一个 queue
和 returns 一个 deque
。事实上,returns 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 对这种类型的命名方式都很丑陋。
第二行获取指向Q
中字段c
的成员指针。它通过 C++ 类型系统中的漏洞来实现这一点。 &hack::c
在逻辑上属于 C hack::*
类型——指向 hack
类型的 class 中的 C
类型成员的指针。事实上,这就是为什么我们可以在 hack
的 static
成员中访问它。但是问题中的c
实际上是在Q
中,所以C++中表达式的实际类型是C Q::*
:指向Q
.[=71的成员变量的指针=]
不能在hack
中直接获取这个成员指针——&Q::c
是非法的,但&hack::c
是非法的。
您可以将成员指针视为 'typed offsets' 到另一种类型:&hack::c
是 Q
中 c
的 "offset" 并且知道它是类型 C
。现在这不是真的——它是一些不透明的值告诉编译器如何从 Q
得到 c
——但它有助于以这种方式思考它(并且它可能被实现简单情况下的方式)。
然后我们使用这个成员指针和 Q&
从 Q
中得到 c
。获取成员指针受保护限制:使用它不是!我们的做法是使用运算符.*
,它是成员解引用运算符,你可以在右边传递成员函数指针或成员,以及class 实例在左边。
instance .* member_ptr
是在instance
中通过member_ptr
查找成员"pointed to" 的表达式。在原始代码中,所有内容都在一行中完成:
instance .* &class_name::member_name
所以看起来好像有一个运算符 .*&
。
}
};
然后我们关闭静态方法和hack
class,还有:
return hack::get(q);
}
调用它。这种技术可以访问 protected
状态:没有它,protected
成员只能在同一实例的子 class 中访问。使用它,我们可以访问 any 实例的 protected
成员,而不会违反任何标准。