一.定义

       简单地说,const引用是指–指向const的引用(其实这样说不恰当,在我的理解中,const引用中的const只是限定了不能通过此引用去修改变量的值),和const指针一样,const引用可以与常量绑定,也可以与变量绑定,只是不能通过这个const引用来改变绑定对象的值,就如之后要讲的const指针类似。
       另外,引用的对象是常量还是非常量可以决定其能参与的操作,却无论如何都不会影响到引用和对象的绑定关系。

二.应用

1、初始化的必要性: 一旦引用已经定义,它就不能再指向其他的对象.这就是为什么它要被初始化的原因。
2、const引用可以用不同类型的对象初始化(只要能从一种类型转换到另一种类型即可),也可以是不可寻址的值,如文字常量。例如:

int i=42;
const int &r1=i;          
1. const int &rb = 1;//允许将引用绑定到字面值上  
2. const int &rc = r1 * 2;//允许将引用绑定到常量表达式上 不可寻址  
3. double d = 3.14;  
   const int &rd = d;//这是允许的 但是如果是非const引用就不行

       上面的三个例子执行时,由于初始值为不可寻址的值,或者类型不匹配的对象或者是字面值常量,编译器会生成临时对象,并将常量引用绑定到该临时对象上;如:3中,编译器会先将double的d经过类型转换放到一个整形的临时对象中,然后将常量引用绑定到这个临时对象,如下:

const int tmp = d; //生成临时变量  
const int &rd = tmp; //绑定临时变量

       因此,对于普通的引用,绑定对象必须严格的匹配: 因为如果类型不匹配,那么定义的引用会被绑定到一个临时对象上去,而在对引用做相应的操作的时候,实际上操作的是临时对象,并非初始化时想要绑定的对象!而对于常量引用,因为其并不能修改绑定的对象,所以将其绑定到临时对象也是可以的。

3、不允许非const引用指向需要临时对象的对象或值,对于普通的引用,绑定对象必须严格的匹配,即,编译器产生临时变量的时候引用必须为const!!!

int a = 2;
int &ref1 = a;// OK.有过渡变量。
const int &ref2 = 2;// OK.编译器产生临时变量,需要const引用



int iv = 100;
int *&pir = &iv;//错误,非const引用对需要临时对象的引用(非常量初始值必须为左值) 
        //因为pir为非常量引用,而iv的地址值不是对象,编译器会产生临时对象存储iv的地址值 
const int* &pir = &iv;//错误 因为pir也不是常量引用,等价于 int const *&pir = &iv; pir为绑定到一个指向int常量的指针的普通引用; 
int *const &pir = &iv;//ok  注意与上面的差别 顶层const和底层const 



int *pa = &iv;  
const int *&pir = pa;   //正确 pa是左值



const int ival = 1024;
int *&pi_ref = &ival;    //错误,非const引用是非法的
//修改
const int ival = 1024;
const int *const &pi_ref = &ival;    //两个const代表的含义

const引用绑定到类型不匹配的对象类型上时发生了什么:

double d=3.1415;  
const int &rd=d;

       执行const int &rd=d时,发生了这种情况:const int temp=d;const int &rd=temp;所谓临时变量就是编译器需要一个空间暂存表达式的求值结果时临时创建的未命名的对象。而假如rd不是一个常量引用,在对rd赋值时,就会改变rd所绑定对象的值。但此时绑定的对象是一个临时的量,它没有名字,而不是绑定了d,既然rd绑定了d,肯定是想通过rd改变d的值,否则干嘛将d绑定到rd呢?但是此时非const修饰的rd改变不了d的值,那绑定也就无意义,所以编译器不允许这样做。

4、const引用仅对引用可进行的操作作了限定,而对引用的对象本身是不是const没有做限定,所以我们仍然可以改变其指向对象的值,只是不能通过引用:

#include <iostream>
using namespace std;
int main()
{
     int val = 1024;
     const int &ir = val;
     val++;
     //ir++;   不能通过引用来更改
     cout << val << " " << ir << endl;
     return 0;
 }

       如果我们通过ir来改变val的值,编译时会出错。但是我们仍然可以通过val直接改变其值。

三.拓展(由“非常量初始值必须为左值”所想到的)

四.总结

       最后自己的理解就是,const引用只是表明,保证不会通过此引用间接的改变被引用的对象!const引用表示,试图通过此引用去(间接)改变其引用的对象的值时,编译器会报错!这并不意味着,此引用所引用的对象也因此变成const类型了。我们仍然可以改变其指向对象的值,只是不能通过引用。
        常量引用只有2种情况会绑定到实际的对象:一是常量引用的初始值为const对象,且该对象类型与常量引用类型相同(如const int i ; const int &r = i;);二是常量引用的初始值为非const对象,且该对象也与常量引用类型(除去const的类型)相同(如int i; const int &r = i;)。这种情况下,绑定的非const对象内容可以用其他普通引用改变。