C++ 关于C++;运营商;地址;及;范围解析“;

C++ 关于C++;运营商;地址;及;范围解析“;,c++,operator-precedence,pointer-to-member,C++,Operator Precedence,Pointer To Member,您好,我有一个编译器错误的代码(错误来自Microsoft Visual Studio 2008): 虽然此代码没有错误: class B { protected: int b; }; class A : public B { public: void foo() { &(B::b); } }; 根据我对运算符优先级的了解,这两个代码段似乎是等效的,因为:的优先级高于&(例如,请参见“”第137页的表2) 但他们是不同的。。。我认为它与“指向数据成员的指针”有关,但我

您好,我有一个编译器错误的代码(错误来自Microsoft Visual Studio 2008):

虽然此代码没有错误:

class B {
protected:
    int b;
};

class A : public B {
public:
    void foo() { &(B::b); }
};
根据我对运算符优先级的了解,这两个代码段似乎是等效的,因为
的优先级高于
&
(例如,请参见“”第137页的表2)

但他们是不同的。。。我认为它与“指向数据成员的指针”有关,但我不知道它如何适合运算符优先级


有什么解释吗?

在第一种情况下,您使用的是指向成员
B::B
的指针地址。由于此类指针不是
a
父对象的成员,而是单独的对象,因此无法通过受保护的机制访问它

在它工作的第二种情况下,您需要询问
b
的特定实例的地址,用它的基类对其进行限定,以便在多重继承的情况下,编译器知道您指的是哪个基类。在此上下文中,受保护的属性是可见的

请注意,这将编译:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(){ &A::b; }  // Note here &A:: instead of &B::
};
作为一个添加的示例,它不起作用的原因与以下(希望更熟悉)代码不起作用的原因相同:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(const B* b_obj) { b_obj->b; }
};

当您尝试返回值时,这两个语句之间的差异变得更加明显:

int*     foo()    { return &(B::b);}  // This is a pointer to an int


int A::* foo()    { return &B::b; }   // This is a pointer to a member of type int
您要做的是通过对象访问它:

int A::* foo()    { return &A::b; }   // This is a pointer to a member of type int
从A开始,您可以访问它。

通过B访问它就像从外部访问它一样,从而触发访问说明符。

这只是一个补充。
§5.3.1/2规定:

一元&运算符的结果为 指向其操作数的指针。操作数 应为左值或合格id。 在第一种情况下,如果 表达式是“T”,是 结果是“指向T的指针” …
暂时 限定id。。。如果成员是 类型C类的非静态成员 T、 结果的类型是“指针” 类型为T的C类成员。”

根据§5.1/7,
B::B
属于限定id情况,但
(B::B)
不属于限定id情况。
因此,编译器将其解释为左值。

如果优先级错误,那么肯定是(不同的)语法错误?请注意区别:
int*i=&(a::b)但是
inta::*m=&A::b它还将编译
&此->B::B
@Gene Bushuyev对,这完全等同于OP的第二个(工作)示例:获取父级特定
b
成员的地址,而不是一般的指向成员的指针。标准中有任何关于语法和差异的引用吗?这种语法
&(B::B)
如何表示
B
属于
a
的特定实例?@Nawaz:
B::B
是典型的类消歧语法,可用于引用数据成员或方法。只是括号和
&
之间的互动让人惊讶。@Matthieu:是的。我理解
B::B
的意思。实际上我想问的是,括号有什么特别之处,使其产生差异?在我看来,这更好地解释了差异+1“通过B访问它就像是从外部访问它,从而触发访问说明符。”我认为这是不正确的。OP的第二个例子证明了这一点。另外,假设A包含另一个名为
b
shadowing
b::b
的属性。然后你可以用
&(A::b)
&(b::b)
来区分它们。@Tilman Vogel:我不同意。这就是为什么我在上面展示了如何通过and运算符实际生成的内容来区分两者。
int A::* foo()    { return &A::b; }   // This is a pointer to a member of type int