为什么不能将非 const 引用初始化为不同类型的对象?
Why non const reference cannot be initialized to an object of different type?
我正在读这本书,上面写着我们可以将一种类型的 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;
}
它的工作原理是一样的,为什么它没有在编译器中预先配置?
如果编译器必须执行从一种类型到另一种类型的隐式转换,这意味着它必须创建一个临时文件来保存转换后的值。
non-const 引用无法绑定到临时文件。期间.
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;
}
简而言之,它是为了帮助您避免错误。暂时假设您可以将对象分配给另一种类型的 non-const 引用,如:
// DISCLAIMER: bad code; does not compile
int a = 10;
double &x = a;
x = 2.0;
这意味着什么?第二行意味着 x
是 a
的别名,暗示对 x
的更改反映在 a
中。如果您不打算暗示这一点,那么非 const
参考不是正确的工具。 (如果 x
没有变化,请使用 const
引用。如果更改不应反映在 a
中,请使用副本而不是引用。)所以第三个行应将 a
的值设置为 2
。然而它不能。
隐式转换很容易 one-way。可能没有反向转换。当然,在这个具体的例子中,将浮点数 2.0
转换为整数 2
是没有问题的,但这是一个特例。当您查看更复杂的场景时,尤其是涉及 类 而不是基本类型的场景时,反向转换甚至可能没有意义。通过引用修改不是语言可以保证的,所以为了一致性在所有情况下都是禁止的。
隐式转换涉及创建一个临时对象。如果你编译 const double &x = a;
行,编译器会做你的代码做的同样的事情:创建一个新的 float
对象并让 x
引用这个新对象。在编译器版本中,float
对象没有名称,而在您的代码中,它被称为 temp
。在您的代码中,如果您尝试修改 x
,修改将出现在 temp
中,但不会出现在 a
中,因为它们是不同的对象。与编译器的版本相同——如果您能够通过引用进行修改,您将修改临时对象,而不是原始对象。这破坏了引用的语义。
结果是,如果您认为需要对不同类型(需要转换的对象)的非 const
引用,则您的逻辑可能有问题。编译器可以快速识别这一点并告诉您您正在尝试的东西可能不会像您认为的那样工作。这是一个没有已知效用的陷阱,所以大的橙色锥体在这里可以防止粗心的人。不要浪费时间测试您的可执行文件,因为已经发现了错误。
允许编译器在 compile-time 处指出此 near-certain 错误,为您省去调试 run-time 症状的麻烦。
我正在读这本书,上面写着我们可以将一种类型的 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;
}
它的工作原理是一样的,为什么它没有在编译器中预先配置?
如果编译器必须执行从一种类型到另一种类型的隐式转换,这意味着它必须创建一个临时文件来保存转换后的值。
non-const 引用无法绑定到临时文件。期间.
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;
}
简而言之,它是为了帮助您避免错误。暂时假设您可以将对象分配给另一种类型的 non-const 引用,如:
// DISCLAIMER: bad code; does not compile
int a = 10;
double &x = a;
x = 2.0;
这意味着什么?第二行意味着 x
是 a
的别名,暗示对 x
的更改反映在 a
中。如果您不打算暗示这一点,那么非 const
参考不是正确的工具。 (如果 x
没有变化,请使用 const
引用。如果更改不应反映在 a
中,请使用副本而不是引用。)所以第三个行应将 a
的值设置为 2
。然而它不能。
隐式转换很容易 one-way。可能没有反向转换。当然,在这个具体的例子中,将浮点数
2.0
转换为整数2
是没有问题的,但这是一个特例。当您查看更复杂的场景时,尤其是涉及 类 而不是基本类型的场景时,反向转换甚至可能没有意义。通过引用修改不是语言可以保证的,所以为了一致性在所有情况下都是禁止的。隐式转换涉及创建一个临时对象。如果你编译
const double &x = a;
行,编译器会做你的代码做的同样的事情:创建一个新的float
对象并让x
引用这个新对象。在编译器版本中,float
对象没有名称,而在您的代码中,它被称为temp
。在您的代码中,如果您尝试修改x
,修改将出现在temp
中,但不会出现在a
中,因为它们是不同的对象。与编译器的版本相同——如果您能够通过引用进行修改,您将修改临时对象,而不是原始对象。这破坏了引用的语义。
结果是,如果您认为需要对不同类型(需要转换的对象)的非 const
引用,则您的逻辑可能有问题。编译器可以快速识别这一点并告诉您您正在尝试的东西可能不会像您认为的那样工作。这是一个没有已知效用的陷阱,所以大的橙色锥体在这里可以防止粗心的人。不要浪费时间测试您的可执行文件,因为已经发现了错误。