可能需要禁止通过引用修改它指向的变量的值,为此可在声明引用时使用关键字 const:
int original = 30;
const int& constRef = original;
constRef = 40; // Not allowed: constRef can’ t change value in original
int& ref2 = constRef; // Not allowed: ref2 is not const
const int& constRef2 = constRef; // OK
可以把引用绑定到const对象上,就像绑定到其他对象一样,我们称之为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改他所绑定的对象:
const int ci=1024;
const int &r1=ci; //正确;引用及其对应的对象都是常量;
r1=42; //错误,r1是对常量的引用
int &r2=ci; //错误;试图让一个非常量引用指向一个常量对象
因为不允许直接为ci赋值,当然也就不能通过引用去改变ci。因此,对r2的初始化是错误的。假设该初始化合法,则可以通过r2来改变它引用对象的值,这显然是不正确的。
术语:常量引用是对const的引用
c++程序员们经常把词组“对const的引用”简称为“常量引用”,这一简称还是挺靠谱的,不过前提是你得时刻记得这个就是简称。
严格来说,并不存在常量引用。因为引用不是一个对象,所以我们没法让引用本身恒定不变。事实上,由于c++语言本身并不允许随意改变引用所绑定的对象,所以从这层意义上理解所有的引用又都算是常量。引用的对象是常量还是非常量可以决定其所能参与的操作,却无论如何都不会影响到引用和对象的绑定关系本身。
初始化和对 const 的引用
之前提到的引用的类型必须与其所引用的对象类型一致,但是有两个例外。第一种例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式:
int i=42;
const int &r1=i;//允许将const int&绑定到一个普通int 对象上
const int &r2=42;
const int &r3=r1*3;
int &r4=r1*2;//错误;r4是一个普通的非常量引用
要想理解这种例外情况的原因,最简单的办法是弄清楚当一个常量引用被绑定到另外一种类型上时到底发生了什么:
double dval=3.14;
const int &ri=dval;
此处ri引用了一个int 型的数。对ri的操作应该是整数运算,但dval却是一个双精度浮点数而非整数。此时为了确保让ri绑定一个整数,编译器把上述代码变成了如下形式:
const int temp=dval; //由双精度浮点数生成一个临时的整型常量
const int &ri=temp; //让ri绑定到这个临时量
在这种情况下,ri绑定到了一个临时量对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。c++程序员们常常把临时对象简称为临时量。
当ri不是常量时,如果执行了类似于上面的初始化过程将带来什么样的结果。如果ri不是常量,就允许对ri赋值,这样就会改变ri所引用对象的值。注意,此时绑定的对象是一个临时量而非dval。程序员既然让ri引用dval,就肯定想通过ri改变dval 的值否则干什么要给ri赋值呢?如此看来,既然大家基本上不会想着把引用绑定到临时变量上,c++语言也就把这种行为归为非法。
对const的引用可能引用一个并非 const 的对象
必须认识到,常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是否是一个常量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变他的值:
int i=42;
int &ri=i;
const int &r2=i;
ri= 0; //ri非常量,i的值修改为0
r2=0; //错误:r2是一个常量引用
该文章会更新,欢迎大家批评指正。
推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程