.*& 运算符的作用是什么?

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::Memberobj.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;

CQ 的底层容器——它是 deque<int>.

C & get (Q &q) {

get 需要一个 queue 和 returns 一个 deque。事实上,returns dequequeue 包裹起来:按常规方式,这是不可能的。

  struct hack : private Q {

hack 是函数的局部类型。它继承自Q,只有一个静态成员函数。从它的名字,你可能会怀疑它是一个黑客。你是对的。

没有实例化 hack

    static C & get (Q &q) {

hack::getget 本身具有相同的签名。事实上,我们将 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 类型成员的指针。事实上,这就是为什么我们可以在 hackstatic 成员中访问它。但是问题中的c实际上是在Q中,所以C++中表达式的实际类型是C Q::*:指向Q.[=71的成员变量的指针=]

不能在hack中直接获取这个成员指针——&Q::c是非法的,但&hack::c是非法的。

您可以将成员指针视为 'typed offsets' 到另一种类型:&hack::cQc 的 "offset" 并且知道它是类型 C。现在这不是真的——它是一些不透明的值告诉编译器如何从 Q 得到 c——但它有助于以这种方式思考它(并且它可能被实现简单情况下的方式)。

然后我们使用这个成员指针和 Q&Q 中得到 c。获取成员指针受保护限制:使用它不是!我们的做法是使用运算符.*,它是成员解引用运算符,你可以在右边传递成员函数指针成员,以及class 实例在左边。

instance .* member_ptr 是在instance 中通过member_ptr 查找成员"pointed to" 的表达式。在原始代码中,所有内容都在一行中完成:

instance .* &class_name::member_name

所以看起来好像有一个运算符 .*&

    }
  };

然后我们关闭静态方法和hackclass,还有:

  return hack::get(q);
}

调用它。这种技术可以访问 protected 状态:没有它,protected 成员只能在同一实例的子 class 中访问。使用它,我们可以访问 any 实例的 protected 成员,而不会违反任何标准。