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; }
::
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 the foo
function,why is that?&C::c
is different in printf
and std::cout
, why is that?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).
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.
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.
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.
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)));
The relevant part of the standard is [expr.unary.op], saying:
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
” [...]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With