2.4.1 const常量的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。与普通的引用不同的是,对常量的引用不能被修改。
C++程序员们经常把词组“对const的引用”简称为“常量引用”,这一简称还是挺靠谱的,不过前提是你得时刻记得这就是个简称而已。
严格来说,并不存在常量引用。因为引用不是一个对象,所以我们没法让引用本身恒定不变。事实上,由于C++语言并不允许随意改变引用所绑定的对象,所以从这层意义上理解所有的引用又都算是常量。引用的对象是常量还是非常量可以决定其所能参与的操作,却无论如何都不会影响到引用和对象的绑定关系本身。
初始化和对const的引用
2.3.1节(第46页)提到,引用的类型必须与其所引用对象的类型致, 但是有两个例外。第种例外情况就是 在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成(参见2.1.2 节,第32页)引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,其至是个一般表达式:
int 1=42;
const int &r1 = 1;
//允许将const int&绑定到一个普通int对象上
const int &r2 = 42;
//正确: r1是一个常量引用
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 - dval;
//由双精度浮点数生成一个临时的整型常量
const int 6ri = temp;
//让ri绑定这个临时量
在这种情况下,ri 绑定了一个临时量(temporary) 对象。所谓临时量对象就是当编译器需要个空间来暂存 表达式的求值结果时临时创建的一个未命名的对象。C++程序员们常常把临时量对象简称为临时量。
接下来探讨当ri不是常量时,如果执行了类似于上面的初始化过程将带来什么样的后果。如果ri不是常量,就允许对ri赋值,这样就会改变ri所引用对象的值。注意,此时绑定的对象是个临时量而非 dval.程序员既然让 ri引用 dval, 就肯定想通过ri改变dval的值,否则干什么要给ri赋值呢?如此看来,既然大家基本上不会想着把引用绑定到临时量上,C++语言也就把这种行为归为非法。
对const的引用可能引用一个并非const的对象
必须认识到,常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值:inti=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赋值,也可以通过像rl - -样绑定到i的其他引用来修改。
2.1.2 指针和const
与引用一样, 也可以令指针指向常量或非常量。类似于常量引用(参见2.4.1节,第54页),指向常量的指针(pointer to const)不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针:
const double pi = 3.14;
// pi是个常量,它的值不能改变
double *ptr = π
//错误: ptr是一个普通指针
const double *cptr = π
//正确: cptr可以指向一个双精度常量
*cptr = 42;
//错误:不能给*cptr赋值
2.3.2节(第47页)提到,指针的类型必须与其所指对象的类型-致,但是有两个例外。第一种例外情况是允许令一个指向常量的指针指向一个非常量对象:
double dval = 3. 14;
// dval是一个双精度浮点数,它的值可以改变
cptr = &dval;
//正确:但是不能通过cptr改变dval的值
和常量引用一样,指向常量的指针也没有规定其所指的对象必须是一个常量。所谓指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变。
试试这样想吧:所谓指向常量的指针或引用,不过是指针或引用“自以为是”罢了,它们觉得自己指向了常量,所以自觉地不去改变所指对象的值。