引用(reference) 为对象起了另外一个名字,引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。
通过将声明符写成 &d
的形式来定义引用类型,其中 d
是声明的变量名。
引用即别名,定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的:
- 为引用赋值,实际上是把值赋给了与引用绑定的对象;
- 获取引用的值,实际上是获取了与引用绑定的对象的值;
- 同理,以引用作为初始值,实际上是以与引用绑定的对象作为初始值。
int ival = 1024;
int &refVal = ival; // refVal 指向 ival,refVal 是 ival的别名
refVal = 2; // 把 2 赋给 refVal 指向的对象,此处即是赋给了ival
int ii = refVal; // 与 ii = ival 执行结果一样
引用定义应注意的问题
(1)定义引用时,一定要对其进行初始化。
int $refVal2; // 报错:引用必须被初始化
(2)一旦初始化完成,引用将和它的初始值对象一直绑定在一起,无法令引用重新绑定到另一个对象。
int ival = 1024;
int ival2 = 2048;
int &refVal = ival;
refVal = ival2; // 并不是重新绑定,而是将 ival 的值变成了 2048
(3)引用只能绑定在对象(这里与变量等价)上,不能与字面值或者某个表达式的计算结果绑定在一起。
int &refVal = 10; // 错误:引用类型的初始值必须是一个对象
且引用初始化时,引用的类型要与与之绑定的对象严格匹配。
// 例1:
double val = 3.14;
int $refVal = val; // 错误:此处引用类型的初始值必须是 int 型对象
// 例2:
int i = 0, &r1 = i; // r1 已经正确初始化了
double d = 0, &r2 = d; // r2 已经正确初始化了
r1 = d; // 正确,但隐式转换
r1 = r2; // 正确,但隐式转换
r2 = i; // 正确,但隐式转换
r2 = r2; // 正确,但隐式转换
但也有两个例外:
- 对常量引用初始化时,允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定到非常量的对象、字面值、甚至是个一般表达式;
- 存在继承关系的类,可以讲基类的指针或引用绑定到派生类对象上。
(4)因为引用本身不是一个对象,所以不能定义引用的引用,即 int &&refVal
是不合法的。
(5)允许在一条语句中定义多个引用,其中每个引用标识符都必须以符号 & \& & 开头。
int i = 1024, i2 = 2048; // i 和 i2 都是 int
int &r = i, r2 = i2; // r 是一个引用且与 i 绑定在一起,r2 是 int
int &r3 = i3, &r4 = i2; // r3 和 r4 都是引用。