2.4 引用
引用是某个对象(即变量)的别名,即某个对象的替代名称(相当一个人的第二名称)。在C语言中没有引用这一概念,它是C++引入的新概念。引用由符号&引导定义,形式如下:
类型 &引用名=变量名;
例如:
int i=9; //L1 int &ir=i; //L2
语句L2定义ir为i的别名,相当于i还有一个名字叫ir。对ir的操作就是对i的操作。
【例2-5】 引用的简单例子。
//Eg2-5.cpp #include<iostream.h> void main(){ int i=9; int& ir=i; cout<<"i= "<<i<<" "<<"ir="<<ir<<endl; ir=20; cout<<"i="<<i<<" "<<"ir="<<ir<<endl; i=12; cout<<"i="<<i<<" "<<"ir="<<ir<<endl; cout<<"i的地址是:"<<&i<<endl; cout<<"ir的地址是:"<<&ir<<endl; }
本程序的运行结果如下:
i= 9 ir=9 i=20 ir=20 i=12 ir=12 i的地址是:0x0012FF34 ir的地址是:0x0012FF34
从结果可以看出,ir和i其实是同一内存变量,对ir的操作实际就是对i的操作。
使用引用时需要注意以下几个问题:① 在定义引用时,引用符&与指针运算符一样,在类型和引用名之间的位置是灵活的,以下几种定义完全相同。
int& ir=i; int & ir=i; int &ir=i;
② 在变量声明时出现的&才是引用运算符(包括函数参数声明和函数返回类型的声明),其他地方出现的&都是地址操作符。
int i; int &r=i; //引用 int& f(int &i1,int &); //引用参数,函数返回引用 int *p=&i; //&取i的地址 cout<<&p; //&取p的地址 cout<<&i; //&取i的地址
③ 引用必须在定义时初始化,不能在定义完成后再给它赋值,为引用提供的初始值,可以是一个变量,也可以是另一个引用名;同一个变量可以定义多个引用。
float f; //L1 float &fr; //L2,错误,fr未初始化 float &r1=f; //L3 float &r2=f; //L4 float &r3=r1; //L5
这样定义后,r1、r2、r3都是f的别名,对它们的任何运算都是对f的运算。
④ 引用实际是一种隐式指针,但它与指针的用法存在区别。
【例2-6】 引用与指针的区别。
//Eg2-6.cpp void main(){ int i=9; //L1 int *pi=&i; //L2 int &ir=i; //L3 *pi=2; //L4 ir=8; //L5 }
语句L1、L2、L3定义的变量情形如下所示:
pi是指针,ir是引用。语句L4是指针的解引用形式,把i所对应的内存值改为2。语句L5是引用的使用形式,把i对应的内存值改为8。
虽然引用实质上也是一种指针,但它与指针至少存在两点区别:❶ 指针必须通过解引用运算符“*”才能访问它所指向的内存单元,而引用不需要通过“*”就能够访问它所代表的内存单元,与普通变量的访问方法差不多;❷ 指针是一个变量,可以对它重新赋值,让它指向另外的地址,但引用必须在定义时进行初始化,并且一经定义就再也不能作为其他变量的引用了。
⑤ 当用&运算符获取一个引用的地址时,实际取出的是引用对应的变量的地址。例如:
int i=9; int &ir=i; int *pi=&ir;
pi实际指向的是i,因为ir是i的别名,所以&ir将获得i的内存地址。
⑥ 建立引用时,需要注意以下3个限制:不能建立引用的引用;不能建立引用数组,也不能建立数组的引用;可以建立指针的引用,但不能创建指向引用的指针。例如:
int i=0,a[10]; int &aa=a; //错误,aa是数组的引用 int &ia[5]; //错误,ia是引用数组 int &*ip=i; //错误,ip是指向引用的指针 int &&ii=i; //错误,ii是引用的引用 int *pi=&i; int *&pr=pi; //正确,pr是指针的引用
⑦ 引用与左值。对于每个变量,都有两个与它相关联的值:左值和右值。左值是指变量对应的那块内存区域的地址,是可以“放在赋值符号左边的值”;右值是指变量对应的内存区域中存储的数据值,是可以“放在赋值符号右边的值”。
一般地,赋值语句的左边必须是一个左值。当一个变量名放在赋值语句的左边时,是对它的左值进行操作,即修改它对应的内存区域中的值;当变量放于赋值句的右边或表达式中时,操作的是它的右值,即读取变量对应的内存单元中的值进行相关运算。
常量、表达式都仅是一个右值,所以不能把它们放在赋值句的左边。例如:
int i=1; i=i+10; //L1 i+10=i; //L2,错误,i+10是一个右值,不能放在=的左边 i=10; 10=i; //L3,错误,右值不能放在=的左边
语句L1尽管在“=”的两边都有i,但它们是有区别的。“=”左边取的是i的内存地址(左值),右边取的是i在对应内存中的值1(右值)。
引用是一个左值。也就是说,引用一定与某块内存区域相对应,能够放在赋值符“=”的左边。在C++中,引用主要用来定义函数的参数和函数返回类型。因为引用只需要传递一个对象的地址,在传递大型对象的函数参数或从函数返回大型对象时,可以提高效率。