一、引用(reference)定义
引用(reference),即为对象起了另外一个名字,通过将声明符写成&v的形式来定义引用类型,其中v是声明的变量名。需要说明的是,引用的创建并非对象,而是为一个已经存在的对象所起的另外一个名字。引用定义示例如下:
int v = 8;
int &rv = v;
上述代码中,rv即为变量v的别名。
使用说明:
1. 定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用;
2. 一旦引用的初始化完成,引用将和它的初始值对象一直绑定在一起,且无法重新绑定到另外一个对象;
3. 引用必须初始化。除了“对const的引用”和“存在继承关系的类的引用”情况,其他所有引用的类型都要和与之绑定的对象严格匹配,且只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
二、特殊的引用情况
(一)常量引用
把引用绑定到const限定符上,即为对const的引用,简称常量引用。在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可,尤其允许为一个常量引用绑定非常量的对象、字面值,甚至是一个表达式。
使用说明:
1. 常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未做限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值(如新的普通引用等)。
(二)存在继承关系的类的引用
对于存在继承关系的类,可以将其基类的指针或引用绑定到派生类对象上。该操作有一层极为重要的含义,即当使用基类的引用(或指针)时,实际上我们并不清楚该引用(或指针)所绑定对象的真实类型。
注意事项:
1. 在使用存在继承关系的类型时,必须将一个变量或其他表达式的静态类型(static type)与该表达式表示对象的动态类型(dynamic type)区分开来;
2. 表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型;
3. 动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才可知。
三、常见的引用使用场景
(一)避免对象复制开销——函数参数传递
当需要在函数内部修改函数外部变量的值时,引用是很好的选择。与值传递不同,值传递会创建参数的副本,而引用传递提供了操作原始变量的途径且避免了创建副本的较大性能开销。
(二)实现函数式编程风格的操作链或操作类成员函数——函数返回值
在一些高级的C++编程场景中,特别是涉及到一些类似于函数式编程的操作时,可以使用引用让操作更加连贯,如std::cout<<"字符串"<<“字符串”<<endl;。
如果希望函数返回一个左值(可以出现在赋值语句左边的值)时,可以使用引用返回。这种情况通常用于操作类的成员函数,返回对象内部数据成员的引用,以方便对对象内部状态进行修改。
参考资料:
[1] C++ Primer中文版:第5版 /(美)李普曼(Lippman,S.B.),(美)拉乔伊(Lajoie,J.),(美)默(Moo,B.E.)著;王刚,杨巨峰译. —北京:电子工业出版社,2013.9.