通俗来讲,引用(reference)就是给对象另外一个名字。
1)引用必须被初始化
int &ref; // 错误
int val=10;
int &ref2=val; // ref2指向val(val的另一个名字)
在初始化变量时,初始值会被拷贝到新建的对象中。在定义引用时,程序把引用和它的初始值绑定(bind)在一起,而不是将初始值拷贝到引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另一个对象,因此引用必须初始化。
补充:所谓对象,就是一块存储数据并具有某种类型的内存空间。
2)引用即别名。引用并非对象,它只是另外一个已经存在的对象的名字。
3)引用类型的初始值必须是一个对象。
int &ref3=10; // 错误
4)可以把引用绑定到const对象上,就像绑定到其他对象一样,它被称为对常量的引用(reference to const)。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。
const int cVal= 10;
const int &cRef= cVal; // 正确: 引用及其对应的对象都是常量
cRef=20; // 错误: cRef是对常量的引用
int &ref2= cVal; // 错误: 不能让一个非常量引用指向一个常量对象
5)除了下面的两种例外情况外,所有的引用类型都要和与之绑定的对象严格匹配。
double dVal=20.0;
int %ref4 = dVal; // 错误
第一种例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。【C++注意事项】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是一个普通的非常量引用
下面通过一个示例来说明当一个常量引用被绑定到另一种类型上时到底发生了什么。
double dval= 3.14;
const int &ri= dval;
此处的ri引用了一个int型的数。对ri的操作应该是整数运算,但dval却是一个双精度浮点数而非整数。因此为了确保让ri绑定一个整数,编译器把上述代码变成了如下形式:
cosnt int temp= dval;
const int *ri= temp;
在这种情况下,ri其实是绑定了一个临时量(temporary)对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建一个未命名的对象。临时量对象常被简称为临时量。
如果ri不是常量就会允许对ri赋值,这样就会改变ri所引用对象的值。而此时绑定的对象是一个临时量而非dval。既然用ri引用了dval,那么就是想通过ri修改dval的值了,否则干嘛要给ri赋值呢?那么既然不会想着把引用绑定到临时量上,C++语言便将这种行为归为非法。
6)对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的值。但是可以通过直接赋值或者通过非常量引用来修改。