测试下面的代码,我把输出信息放在评论中.我使用的是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)
::运算符的优先级高于&运算符.我认为&C::c是等于&(C::c),但输出说不然.他们为什么不同?&(C::c)导致主要但不在foo函数中的编译错误,为什么会这样?&C::c是不同的printf和std::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",并且是一个指定prvalueC?::?m.否则,如果表达式的类型是T,结果的类型为"指针T"[...]