&C :: c和&(C :: c)之间有什么区别?

Xia*_*ENG 48 c++

测试下面的代码,我把输出信息放在评论中.我使用的是gcc 4.8.5和Centos 7.2.

#include <iostream>
#include <cstdio>

class C 
{
    public:
        void foo() {
            printf("%p, %p\n", &C::c, &(C::c)); // output value is 0x4, 0x7ffc2e7f52e8
            std::cout << &C::c << std::endl;    // output value is 1
        }
        int a;
        int c;
};

int main(void)
{
    C co;

    printf("%p\n", &C::c);              // output value is 0x4
    std::cout << &C::c << std::endl;    // output value is 1

//    printf("%p\n", &(C::c));   // compile error, invalid use of non-static data member 'C::c'

    co.foo();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
  1. 根据C++运算符Precedence,::运算符的优先级高于&运算符.我认为&C::c是等于&(C::c),但输出说不然.他们为什么不同?
  2. &(C::c)导致主要但不在foo函数中的编译错误,为什么会这样?
  3. 的价值&C::c是不同的printfstd::cout,这是为什么?

mel*_*ene 47

C++将两种形式的操作数区分为运算&符,一般是lvalues,特别是(限定的)标识符.在&C::c操作数中&是一个限定标识符(即只是一个名称),而在&(C::c)操作数中是一般表达式(因为(不能是名称的一部分).

限定标识符表单有一个特殊情况:如果它引用类的非静态成员(如您的C::c),则&返回一个称为"指向C成员的指针"的特殊值.有关成员指针的更多信息,请参见此处.

&(C::c)没有特例的情况下.C::c正常解决并失败,因为没有对象来获取c成员.至少那是发生的事情main; 在C(像你foo)的方法中有一个隐含的this对象,所以C::c实际意味着this->c那里.

至于为什么输出是不同的printf对比cout:当您尝试打印带有成员指针<<,它被隐式转换为bool,产生false如果它是一个空指针和true其他.false印刷为0; true打印为1.你的成员指针不是null,所以你得到1.这是从正常的指针,这是隐式转换为不同的void *,打印输出为地址,但构件指针不能被转换到void *这样的只适用过载operator<<是一个给bool.请参阅https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt#Notes.

请注意,技术上您的printf调用具有未定义的行为.%p采取一个void *,你传递不同类型的指针.在正常的函数调用从自动转换T *void *会踢的,但是printf是一个可变参数的功能,可提供无类型上下文参数列表,所以你需要手动转换:

printf("%p\n", static_cast<void *>(&(C::c)));
Run Code Online (Sandbox Code Playgroud)

标准的相关部分是[expr.unary.op],说:

一元运算&符的结果是指向其操作数的指针.操作数应为左值或限定ID.如果操作数是一个合格-ID命名非静态或变体构件m某些类的C类型T,结果类型"指针类的成员C类型的T",并且是一个指定prvalue C?::?m.否则,如果表达式的类型是T,结果的类型为"指针T"[...]