【问题标题】:Pointer-to-member confusion指向成员的混淆
【发布时间】:2016-04-28 09:34:20
【问题描述】:

我正在尝试了解此程序中引发的错误的一致性:

#include <iostream>

class A{
public:
    void test();
    int x = 10;

};

void A::test(){

    std::cout << x << std::endl; //(1)
    std::cout << A::x << std::endl; //(2)

    int* p = &x;
    //int* q = &A::x; //error: cannot convert 'int A::*' to 'int*' in initialization| //(3)


}

int main(){

    const int A::* a = &A::x; //(4)

    A b;

    b.test();

}

输出为10 10。我标记了程序的 4 点,但 (3) 是我最关心的:

  1. x 通常从成员函数内部获取。
  2. 使用范围运算符获取对象的x,并返回对象x 的左值。
  3. 鉴于A::x 在(2) 中返回了int 左值,为什么&amp;A::x 不返回int* 而是返回int A::*?范围运算符甚至优先于 &amp; 运算符,因此应首先运行 A::x,在获取地址之前返回一个 int 左值。即这应该与&amp;(A::x) 相同吗? (顺便说一句,添加括号确实有效)。
  4. 当然,这里有点不同,范围运算符引用一个类成员,但没有引用对象。

那么为什么A::x 不返回对象x 的地址,而是返回成员的地址,而忽略::&amp; 之前的优先级?

【问题讨论】:

    标签: c++ c++11 pointer-to-member


    【解决方案1】:

    C++ 标准没有明确指定运算符优先级;可以从语法规则中隐式推导出运算符优先级,但是这种方法无法理解这种不适合传统运算符优先级模型的偶尔出现的特殊情况。

    [expr.unary.op]/3:

    一元&amp; 运算符的结果是指向其操作数的指针。操作数应为左值或qualified-id。如果操作数是 qualified-id 命名某个类C 的非静态或变体成员m 类型为T,结果类型为'指向类C 的成员的类型 T' 是一个prvalue,指定C::m。否则,如果表达式的类型为T,则结果的类型为“指向T”的指针,并且是一个prvalue,它是指定对象的地址或指向指定函数的指针。

    /4:

    仅当使用显式&amp; 并且其操作数是未括在括号中的qualified-id 时,才会形成指向成员的指针。 [ 注意: 也就是说,表达式&amp;(qualified-id),其中qualified-id 括在括号中,不会形成“指向成员的指针”类型的表达式。

    [expr.prim.general]/9:

    一个 nested-name-specifier 表示一个类,可选地后跟关键字template,然后是该类或其基类之一的成员的名称,是一个qualified-id

    如果x 是非联合的非静态成员,那么这一切加起来就是&amp;A::x 形式的表达式的类型为“指向A 类成员x 的指针”类A,运算符优先级对此没有影响。

    【讨论】:

      【解决方案2】:

      基本上,只是选择了语法&amp;A::x(没有变化)来表示指向成员的指针。

      如果你写,例如&amp;(A::x),你会得到你期望的纯指针。

      有关指向成员的指针的更多信息,包括有关此属性的注释,可以找到here

      【讨论】:

      • 我认为如果不这样的话,会导致更多的混乱。相同的标识符和运算符序列,引用完全相同的类型和成员,根据范围意味着两种不同的东西:对我来说听起来很麻烦。
      • @JohnSensebe 绝对。我最初写了“quirk”,但这实际上是一个非常明智的选择,尽管一开始可能看起来很奇怪。
      猜你喜欢
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 2023-03-05
      相关资源
      最近更新 更多