C++的引用
一般所说的引用指的都是左值引用(C++ 11新增了"右值引用”),是为对象起了另外一个名字,可以理解为对象的别名。定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起,因此无法令引用重新绑定到另外一个对象。
引用变量定义
int ival = 1024;
int &refval = ival; //定义引用变量refval,将其绑定到ival,是ival的另外一个名字
int &refval; //报错,引用必须初始化
定义一个引用后,对其进行的所有操作都是对其所绑定对象的操作:
refval = 2; //把2赋给refval所绑定的对象,即将ival修改为2
int ii = refval; //与ii = ival执行结果一样,ii初始值为2
引用变量用在函数中
在C语言中,函数的参数传递有两种方式:值传递和地址传递,C++中有了引用后,因此函数的参数传递新增一种方式:引用传递。
值传递:将实参值拷贝到形参变量中,在函数中对形参变量的操作不会对实参变量产生任何影响。
地址传递:将实参的地址拷贝到形参指针变量中,在函数中可以通过局部指针变量修改实参变量值。
引用传递:不做临时拷贝,形参只是实参的别名而已,所以对形参变量的操作其实就是对实参变量的进行操作。
int foo(int v1, int v2); //值传递,实参被拷贝到形参v1、v2中,对v1、v2的访问和修改对实参不会有任何影响
int foo(int *pv1, int *pv2); //地址传递,实参的地址被拷贝到形参指针变量pv1, pv2中,通过指针pv1, pv2可修改实参值
int foo(int &v1, int &v2); //引用传递,参数v1, v2都是引用,即实参的别名,对v1、v2的修改将改变实参值
右值引用
右值引用是C++ 11新增的引用类型,用于支持对象移动操作。
右值引用就是必须绑定到右值的引用,使用&&定义。
类似左值引用,右值引用也是某个对象的另一个名字。对于左值引用,不能将其绑定到要求转换的表达式、字面常量或是返回右值的表达式,而右值引用完全相反:可以将一个右值引用绑定到这类表达式,但不能讲一个右值引用绑定到一个左值上。
int i = 42;
int &r = i; //正确,r绑定到i
int &&rr = i //错误,不能将右值引用绑定到左值上
int &r2 = i * 42; //错误,i * 42是个字面值
const int &r2 = i * 42; //正确,可以将一个const的引用绑定到右值上
int &&rr2 = i *42; //将rr2绑定到乘法结果(字面值)
int &&rr1 = 42; //正确,字面值常量是右值
int &&rr2 = rr1; //错误,rr1是右值引用变量,而变量都是左值,因此不能将右值引用绑定到变量上,即使是右值引用变量也不行
返回左值引用的函数,连同赋值、下标、解引用和前置递增/递减运算符,都是返回左值的表达式,可以将左值引用绑定到这类表达式的结果上;返回非引用类型的函数,连同算术、关系、位以及后置递增、递减运算符,都生成右值,不能将左值引用绑定到这类表达式上,但可以将一个const的左值引用或一个右值引用绑定到这类表达式上。
右值引用主要用于C++ 11新引入的移动构造函数和移动赋值运算符,这里不涉及。
注意事项(都是说左值引用):
引用必须初始化;
无法令引用重新绑定到另外一个对象;
引用并非对象;
引用不是一个对象,所以不能定义引用的引用;
引用只能绑定到对象上,而不能与字面值或某个表达式的计算结果绑定在一起。