测试下面的代码,我把输出信息放在评论中.我使用的是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
"[...]
归档时间: |
|
查看次数: |
2629 次 |
最近记录: |