& C :: c和&(C :: c)有什么区别? [英] What's the difference between &C::c and &(C::c)?
问题描述
在下面的测试代码中,我将输出信息放入注释中.我当时使用的是gcc 4.8.5和Centos 7.2.
Test code in below and I put the output info in comment. I was using gcc 4.8.5 and 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;
}
- 根据 C ++运算符优先级,
::
运算符的优先级高于&
运算符.我认为& C :: c
等于&(C :: c)
,但输出结果却相反.他们为什么不同? -
&(C :: c)
在main中导致编译错误,但在foo
函数中未引起编译错误,为什么? -
printf
和std :: cout
中& C :: c
的值不同,为什么?
- According to C++ operator Precedence,the
::
operator has higher precedence than the&
operator. I think&C::c
is equal to&(C::c)
, but the output says otherwise. Why are they different? &(C::c)
causes a compile error in main but not in thefoo
function,why is that?- The value of
&C::c
is different inprintf
andstd::cout
, why is that?
推荐答案
C ++将两种类型的操作数区分为&
运算符,即通用的左值和(合格的)标识符.在& C :: c
中,&
的操作数是合格标识符(即只是名称),而在&(C :: c)
操作数是一个通用表达式(因为(
不能是名称的一部分).
C++ distinguishes two forms of operands to the &
operator, lvalues in general and (qualified) identifiers specifically. In &C::c
the operand of &
is a qualified identifier (i.e. just a name) whereas in &(C::c)
the operand is a general expression (because (
cannot be part of a name).
合格标识符形式有一个特殊情况:如果它引用类的非静态成员(例如您的 C :: c
),则&
返回一个特殊的值,称为"C成员的指针".有关成员指针的更多信息,请参见此处.
The qualified identifier form has a special case: If it refers to a non-static member of a class (like your C::c
), &
returns a special value known as a "pointer to member of C". See here for more information about member pointers.
在&(C :: c)
中没有特殊情况. C :: c
可以正常解析,并且会失败,因为没有对象可以获取 c
成员.至少这就是 main
中发生的情况;在 C
的方法(例如您的 foo
)中,存在一个隐式的 this
对象,因此实际上 C :: c
表示在那里 this-> c
.
In &(C::c)
there is no special case. C::c
is resolved normally and fails because there is no object to get a c
member of. At least that's what happens in main
; in methods of C
(like your foo
) there is an implicit this
object, so C::c
actually means this->c
there.
关于为什么 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 .
As for why the output is different for printf
vs. cout
: When you try to print a member pointer with <<
, it is implicitly converted to a bool
, yielding false
if it's a null pointer and true
otherwise. false
is printed as 0
; true
is printed as 1
. Your member pointer is not null, so you get 1
. This is different from normal pointers, which are implicitly converted to void *
and printed as addresses, but member pointers cannot be converted to void *
so the only applicable overload of operator<<
is the one for bool
. See https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt#Notes.
请注意,从技术上讲,您的 printf
调用具有未定义的行为.%p
需要一个 void *
,并且您要向其传递不同类型的指针.在正常的函数调用中,会自动执行从 T *
到 void *
的自动转换,但是 printf
是一个变量自变量函数,不提供任何类型到其参数列表的上下文,因此您需要进行手动转换:
Note that technically your printf
calls have undefined behavior. %p
takes a void *
and you're passing it pointers of different types. In normal function calls the automatic conversion from T *
to void *
would kick in, but printf
is a variable-arguments function that provides no type context to its argument list, so you need a manual conversion:
printf("%p\n", static_cast<void *>(&(C::c)));
该标准的相关部分是 [expr.unary.op] ,说:
一元
&
运算符的结果是指向其操作数的指针.操作数应为左值或 qualified-id .如果操作数是 qualified-id ,则为其命名为T 的某些类
C
的非静态成员或变体成员m
.code>,结果的类型为指向类型为T
的类C
的成员的指针",并且是一个指定C :: m
的prvalue..否则,如果表达式的类型为T
,则结果的类型为指向T
的指针" [...]
The result of the unary
&
operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static or variant memberm
of some classC
with typeT
, the result has type "pointer to member of classC
of typeT
" and is a prvalue designatingC::m
. Otherwise, if the type of the expression isT
, the result has type "pointer toT
" [...]
这篇关于& C :: c和&(C :: c)有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!