This question already has an answer here:
I can't understand this line - dereferencing an address of private member variable or what?

(1个答案)


4年前关闭。




我偶然发现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成员的功能。但是,我不知所措,无法清楚地解释它。 .*&到底发生了什么,为什么允许它?

最佳答案

typedef std::queue<int> Q;
Q是适应queue的容器。
typedef Q::container_type C;
CQ的基础容器-这是deque<int>
C & get (Q &q) {
get接受queue并返回deque。实际上,它返回deque包装的queue:通过常规方式,这是不可能的。
  struct hack : private Q {
hack是函数的本地类型。它继承自Q,并且只有一个静态成员函数。从它的名字,您可能会怀疑它是一个hack。你是对的。

没有hack实例化。
    static C & get (Q &q) {
hack::getget本身具有相同的签名。实际上,我们将get的所有工作委托(delegate)给此方法。
      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类型的成员的指针。实际上,这就是为什么我们可以在statichack成员中访问它的原因。但是有问题的c实际上在Q中,因此C++中表达式的实际类型是C Q::*:指向Q成员变量的指针。

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

您可以将成员指针视为另一种类型的“类型化偏移量”:&hack::ccQ的“偏移量”,并且知道其类型为C。现在这不是真的-它是一个不透明的值,告诉编译器如何从c中获取Q,但是它有助于以这种方式思考(在简单的情况下也可以以这种方式实现)。

然后,我们将此成员指针与Q&一起使用,以从c中获取Q。获取成员指针受到保护的约束:使用它不是!我们的方法是使用运算符.*,它是成员取消引用运算符,您可以在右侧传递成员函数指针或成员,在左侧传递类实例。
instance .* member_ptr是一个表达式,可在member_ptr中找到instance“指向”的成员。在原始代码中,所有操作都在一行上完成:
instance .* &class_name::member_name

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

然后关闭静态方法和hack类,然后:
  return hack::get(q);
}

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

10-04 12:35