简而言之,它是为了帮助您避免错误。假设您可以将一个对象分配给另一种类型的非常量引用,如下所示:
// DISCLAIMER: bad code; does not compile
int a = 10;
double &x = a;
x = 2.0;
这意味着什么?第二行意味着 thatx
是 的别名a
,意味着对 的更改x
会反映在 中a
。如果您无意暗示这种含义,那么非const
参考不是正确的工具。(如果对 没有更改x
,请使用const
引用。如果更改不应该反映在 中a
,请使用副本而不是引用。)因此第三行应将值设置a
为2
。然而它不能。
隐式转换很容易是单向的。可能没有反向转换。当然,在这个特定的例子中,将浮点数转换2.0
为整数2
是没有问题的,但这是一种特殊情况。当您查看更复杂的场景时,尤其是涉及类而不是基本类型的场景时,反向转换甚至可能没有意义。通过引用进行修改不是语言可以保证的,因此为了保持一致性,在任何情况下都禁止。
隐式转换涉及制作一个临时对象。如果您编译该行const double &x = a;
,编译器将执行与您的代码相同的操作:创建一个新float
对象并x
引用该新对象。在编译器的版本中,该float
对象没有名称,而在您的代码中,它被称为temp
. 在您的代码中,如果您尝试修改x
,则修改将出现在 中temp
,但不会出现在 中,a
因为它们是不同的对象。编译器的版本也是如此——如果您能够通过引用进行修改,那么您将修改临时对象,而不是原始对象。这打破了引用的语义。
结果是,如果您认为需要const
对不同类型的对象(需要转换的对象)进行非引用,那么您的逻辑可能存在问题。编译器可以快速识别这一点,并告诉您您正在尝试一些不会按照您可能认为的方式工作的东西。这是一个没有已知用途的陷阱,所以这里的大橙色锥体可以抵御粗心大意的人。不要浪费时间测试您的可执行文件,因为已经发现了一个错误。
语言规则允许编译器通过在编译时指出这个几乎确定的错误来提供帮助,从而省去了调试运行时症状的麻烦。