为什么非常量引用不能初始化为不同类型的对象



我读过这本书,书中写道,我们可以将一种类型的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;
}

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

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

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

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

实时演示

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

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

这意味着什么?第二行表示xa的别名,这意味着对x的更改反映在a中。如果您不打算这样暗示,那么非const引用就不是合适的工具。(如果x没有更改,请使用const引用。如果更改不应反映在a中,请使用副本而不是引用。(因此,第三行应将a的值设置为2。然而,它不能。

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

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

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

语言规则允许编译器在编译时指出这个几乎确定的错误,从而为您省去调试运行时症状的麻烦。

相关内容

  • 没有找到相关文章

最新更新