& C :: c和&(C :: c)有什么区别? [英] What's the difference between &C::c and &(C::c)?

查看:66
本文介绍了& C :: c和&(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;
}

  1. 根据 C ++运算符优先级 :: 运算符的优先级高于& 运算符.我认为& C :: c 等于&(C :: c),但输出结果却相反.他们为什么不同?
  2. &(C :: c)在main中导致编译错误,但在 foo 函数中未引起编译错误,为什么?
  3. printf std :: cout & C :: c 的值不同,为什么?
  1. 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?
  2. &(C::c) causes a compile error in main but not in the foo function,why is that?
  3. The value of &C::c is different in printf and std::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 member m of some class C with type T, the result has type "pointer to member of class C of type T" and is a prvalue designating C​::​m. Otherwise, if the type of the expression is T, the result has type "pointer to T" [...]

这篇关于&amp; C :: c和&amp;(C :: c)有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆