C++面向对象程序设计
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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++中,引用主要用来定义函数的参数和函数返回类型。因为引用只需要传递一个对象的地址,在传递大型对象的函数参数或从函数返回大型对象时,可以提高效率。