【问题标题】:Why non const reference cannot be initialized to an object of different type?为什么非 const 引用不能初始化为不同类型的对象?
【发布时间】:2020-12-08 03:22:15
【问题描述】:

我在读这本书,上面写着我们可以将一种类型的 const 引用分配给任何其他类型的对象,原因是,内部编译器将 Rvalue 分配给与引用相同类型的对象然后将 const 引用初始化为相同类型的对象,但是,如果这种类型的隐式转换有助于将 const 引用分配给不同类型的对象,那么为什么不可能隐式地进行相同的转换,因为对于这个显式转换。

#include<iostream>
using namespace std;
int main()
{
    int a = 10;

    double temp = (double)a;
    double &x = temp;
    cout << x << endl;
    return 0;
}

也是一样的,为什么编译器里没有预配置?

【问题讨论】:

  • 这个问题真的很难理解。你问的是什么行为?您的示例中的类型匹配,但您的措辞暗示它们不应该。你是说喜欢double &amp;x = a吗?
  • 我们可以将一种类型的 const 引用分配给任何其他类型的对象,原因是内部编译器将 Rvalue 分配给与引用相同类型的对象,然后const 引用被初始化为相同类型的对象 没有代码示例,这句话很难理解。
  • 因为您不能将右值分配给非常量引用?在您的示例中,temp 是一个左值,因此不一样
  • 听起来您认为x 是对a 的引用。不是这种情况。它是对temp 的引用,这是一个doubletemp 被初始化为a 的值,即10
  • 如果你有一个代码序列(可以编译;这不能)int a = 10; double &amp;x = a; x = 7; cout &lt;&lt; a;你希望打印什么值?

标签: c++ reference implicit-conversion explicit-conversion


【解决方案1】:

简而言之,它是为了帮助您避免错误。假设您可以将一个对象分配给另一种类型的非常量引用,如下所示:

// DISCLAIMER: bad code; does not compile
int a = 10;
double &x = a;
x = 2.0;

这意味着什么?第二行意味着xa 的别名,这意味着对x 的更改会反映在a 中。如果您不打算这样做,那么非const 引用不是正确的工具。 (如果x 没有更改,请使用const 引用。如果更改不应该反映在a 中,请使用副本而不是引用。)所以第三行应该设置值a2。但是它不能。

  1. 隐式转换很容易单向转换。可能没有反向转换。当然,在这个具体示例中,将浮点 2.0 转换为整数 2 是没有问题的,但这是一种特殊情况。当您查看更复杂的场景时,尤其是涉及类而不是基本类型的场景时,反向转换甚至可能没有意义。通过引用进行修改不是语言可以保证的,因此为了保持一致性,在任何情况下都禁止。

  2. 隐式转换涉及制作一个临时对象。如果你编译const double &amp;x = a; 行,编译器会做和你的代码一样的事情:创建一个新的float 对象并让x 引用这个新对象。在编译器版本中,float 对象没有名称,而在您的代码中,它被称为 temp。在您的代码中,如果您要尝试修改x,则修改将出现在temp 中,但不会出现在a 中,因为它们是不同的对象。编译器的版本也是如此——如果您能够通过引用进行修改,那么您将修改临时对象,而不是原始对象。这破坏了引用的语义。

结果是,如果您认为需要对不同类型的对象(需要转换的对象)进行非const 引用,则您的逻辑可能存在问题。编译器可以快速识别这一点,并告诉您您正在尝试一些不会按照您可能认为的方式工作的东西。这是一个没有已知用途的陷阱,所以这里的大橙色锥体可以抵御粗心大意的人。不要浪费时间测试您的可执行文件,因为已经发现了一个错误。

The language rules 允许编译器通过在编译时指出这个几乎确定的错误来提供帮助,从而省去调试运行时症状的麻烦。

【讨论】:

    【解决方案2】:

    如果编译器必须执行从一种类型到另一种类型的隐式转换,这意味着它必须创建一个临时值来保存转换后的值。

    非常量引用不能绑定到临时对象。期间。

    一个 const 引用可以,它会延长临时的生命周期。

    换句话说:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        int a = 10;
    
        double &x = (double)a; // ERROR! Can't bind to the temporary double
        cout << x << endl;
    
        const double &x2 = (double)a; // OK! Binds to the temporary double
        cout << x2 << endl;
    
        return 0;
    }
    

    Live Demo

    【讨论】:

    • 但是,我不认为 x2 引用的是 a,而是引用编译器在内部用于隐式转换的临时变量。
    • 是的,这是真的。我在回答中也暗示了这一点。
    猜你喜欢
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 2010-11-30
    • 1970-01-01
    • 2015-02-28
    • 2012-04-29
    相关资源
    最近更新 更多