0

我正在读这本书,上面写着我们可以将一种类型的 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;
}

它的工作方式相同,为什么它没有在编译器中预先配置?

4

2 回答 2

6

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

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

一个 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;
}

现场演示

于 2020-08-18T22:00:36.373 回答
1

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

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

这意味着什么?第二行意味着 thatx是 的别名a,意味着对 的更改x会反映在 中a。如果您无意暗示这种含义,那么非const参考不是正确的工具。(如果对 没有更改x,请使用const引用。如果更改不应该反映在 中a,请使用副本而不是引用。)因此第三行应将值设置a2。然而它不能。

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

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

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

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

于 2020-08-19T03:14:42.973 回答