非const引用的类型必须要和所引用的对象类型一致;但const引用有两种例外:
1.允许用任意表达式作为初始值,只要该表达式能转换成引用的类型
int i = 42; const int &r1 = i; //√ 允许const int绑定到一个普通int对象上 const int &r2 = 42; //√ r2是一个常量引用 const int &r3 = r1 * 2; //√ r3是一个常量引用 int &r4 = r1 * 2; //× r4是一个普通的非常量引用,非常量引用初始值必须为左值 int &r5 = 2; //× 非常量引用初始值必须为左值
2.允许用任意类型对象作为初始值,前提是该类型对象能转换成引用的类型
究其根本原因:非常量引用的初始值必须为左值,常量引用的初始值可以为左值、右值。const引用初始化时,转换成引用类型的对象实为右值。
int i = 2; double &r = i; //编译报错 const double &r = i; //编译通过 //难道这个i不是左值?转换后确实不是 double i = 2; double &r = i; //编译通过 //难道这里的i又是左值了?
为什么会出现这种情况?先来看一个简单的例子
double dval = 0.114514; const int &ri = dval; cout << "ri = " << ri << endl; //运行输出: ri = 0
在这个过程中,由于类型不匹配,编译器把代码改成了:
double dval = 0.114514; const int temp = dval; const int &ri = temp; cout << "ri = " << ri << endl;
这种情况下,ri绑定了一个临时量对象,临时变量都是const,所以没有const的引用会失败
你可以想象以下,如果ri不是常量时,执行了上述初始化过程会带来怎样的后果:
如果ri不是常量。就允许对ri赋值,这样就会改变ri所引用对象的值(此时绑定的是临时变量而非dval),所以C++也把以下这种行为归为非法
double dval = 0.114514; int &ri = dval;//编译报错 cout << "ri = " << ri << endl;
同时注意,对const的引用可能引用一个并非const的对象
对const的引用仅对引用可参与的操作做出了限定,对于引用对象本身是否是一个常量没有做出限定,因此对象也可能是个非常量,允许通过其他途径改变它的值
int i = 42; int &r1 = i; const int &r2 = i; //r2 = 0; //× r2是一个常量引用 cout << "r2 = " << r2 << endl; r2 = 0; //不可通过编译 i = 0; //可通过编译 cout << "r2 = " << r2 << endl; 程序输出: r2 = 42 r2 = 0
 
引用及const引用:等您坐沙发呢!