2.4.1 const的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用(reference to const)。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象:
const int ci = 1024;
const int &ri = ci; // 正确:引用及其对应的对象都是常量
r1 = 42; // 错误:r1是对常量的引用
int &r2 = ci; // 错误:试图让一个非常量引用指向一个常量对象
因为不允许直接为ci赋值,当然也就不能通过引用去改变ci。因此,对r2的初始化是错误的。假设该初始化合法,则可以通过r2来改变它引用对象的值,这显然是不正确的。
术语:常量引用是对const的引用
C++程序员们经常把词组“对const的引用”简称为“常量引用”,这一简称还是挺靠谱的,不过前提是你得时刻记得这个就是简称而已。
严格来说,并不存在常量引用。因为引用不是一个对象,所以我们没法阿让引用本身恒定不变。事实上,由于C++语言并不允许随意改变引用所绑定的对象,所以从这层意义上理解所以的引用又都算是常量。引用的对象是常量还是非常量可以决定其所能参与的操作,却无论如何都不会影响到引用和对象的绑定关系本身。
初始化和对const的引用
2.3.1节(第46页)提到,引用的类型必须与其所引用对象的类型一致,但是有两个例外。第一章例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成(参见2.1.2节,第32页)引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式:
int i = 42;
const int &r1 = i; // 正确:r1是一个常量引用
const int &r2 = 42; // 允许将const int&绑定到一个普通的int对象上
const int &r3 = r1 * 2; // 正确:r3是一个常量引用
int &r4 = r1 * 2; // 错误:r4是一个普通的非常量引用
要想理解这种例外情况的原因,最简单的办法是弄清楚当一个常量引用被绑定到另外一种类型上时到底发生了什么:
double dval = 3.14;
const int &ri = dval;
此处ri引用了一个int型的数,对ri的操作应该是整数运算,但dval确实一个双精度浮点数而非整数。因此为了确保让ri绑定一个整数,编译器把上述代码变成了如下形式:
const int temp = dcal; // 由双精度浮点数生成一个临时的整型变量
const int &ri = temp; // 让ri绑定这个临时量
在这种情况下,ri绑定了一个临时量(temporary)对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时创建的一个未命名的对象。C++程序员们常常把临时量对象简称为临时量。
接下来探讨当ri不是常量时,如果执行了类型于上面的初始化过程将带来什么样的后果。如果ri不是常量,就允许对ri赋值,这样就会改变ri所引用对象的值。注意,此时绑定的对象是一个临时量而非dval。程序员既然让ri引用dval,就肯定想通过ri改变dval的值,否则干什么要给ri赋值呢?如此看来,既然大家基本上不会想着把引用绑定到临时量上,C++语言也就把这种行为归为非法。
对const的引用可能引用一个并非const的对象
必须认识到,常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值:
int i = 42;
int &r1 = i; // 引用ri绑定对象i
const int &r2 = i; // r2也绑定对象i,但是不允许通过r2修改i的值
r1 = 0; // r1并非常量,i的值修改为0
r2 = 0; // 错误:r2是一个常量引用
r2绑定(非常量)整数i是合法的行为。然而,不允许通过r2修改i的值。尽管如此,i的值仍然允许通过其他途径修改,既可以直接给i赋值,也可以通过像r1一样绑定到i的其他引用来修改。
普通的冒险故事提示您:看后求收藏(卧龙小说网http://www.wolongxs.com),接着再看更方便。
好书推荐:《我的剧本世界在自主运行》、《我是舰娘》、《我的师妹是妖女》、《交错世界之学院都市》、《认清现实后,她们开始追夫火葬场》、《好徒儿你就饶了为师伐》、