下面这种情况显然我们是了解的:
const int ci=1024;
const int &rl=ci; //正确:引用及其对应的对象都是常量
r1 =42; //错误:r1是对常量的引用
int &r2=ci; //错误:试图让一个非常量引用指向一个常量对象
初始化和对 const 的引用
2.3.1节(第46页)提到,引用的类型必须与其所引用对象的类型一致,但是有两个例外。第一种例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成(参见2.1.2节,第32页)引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式:
int i= 42;
const int &rl=i; //允许将 const int&绑定到一个普通 int 对象上
const int &r2=42; //正确:r1是一个常量引用
const int &r3=rl*2; //正确:r3 是一个常量引用
int &r4=rl*2; //错误:r4是一个普通的非常量引用
要想理解这种例外情况的原因,最简单的办法是弄清楚当一个常量引用被绑定到另外一种类型上时到底发生了什么:
double dval=3.14;
const int &ri =dval;
此处 ri 引用了一个 int 型的数。对 ri的操作应该是整数运算,但 dva1 却是一个双精度浮点数而非整数。因此为了确保让 ri绑定一个整数,编译器把上述代码变成了如下形式:
const int temp =dval; //由双精度浮点数生成一个临时的整型常量
const int &ri =temp; //让ri绑定这个临时量
int &ri =temp; //非法
在这种情况下,ri 绑定了一个临时量(temporary)对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。C++程序员们常常把临时量对象简称为临时量。
接下来探讨当ri不是常量时,如果执行了类似于上面的初始化过程将带来什么样的后果。如果ri不是常量,就允许对ri赋值,这样就会改变ri所引用对象的值。注意,此时绑定的对象是一个临时量而非 dval。程序员既然让ri引用 aval,就肯定想通过 ri 改变 dval 的值,否则干什么要给ri赋值呢?如此看来,既然大家基本上不会想着把引用绑定到临时量上,C++语言也就把这种行为归为非法。
《C++ Primer》 P55