MENU

C++:引用及其应用

• March 3, 2021 • Read: 269 • 高级语言,学习笔记

引用

引用是个别名,当建立引用时,程序用另一个变量或对象的名字初始化它,从那时起,引用就作为目标的别名而使用,对引用的改动就相当于对目标的改动。

要建立一个引用,需要在目标类型后面接上引用运算符“&”,然后是引用名(可以使用任何合法的变量名)。

例如

int number;
int& oneInt = number;//此时oneInt就相当于number变量,对oneInt操作就相当于对number操作。

注意,引用不是一个变量,它不会占用内存空间,引用声明时也不会改变目标的状态,引用只有声明,没有定义。其次,引用在声明时必须进行初始化,否则编译报错,引用运算符“&”仅在声明的时候使用,其他情况直接使用引用名即可。

引用的声明与指针类似,以下三种声明等价。

int& rInt;
int &rInt;
int & rInt;

引用的操作

//..
int main() {
    int intOne = 5;
    int& rInt = intOne;
    std::cout<<"intOne:"<<intOne<<endl;
    std::cout<<"rInt:"<<rInt<< endl;
    std::cout<<"&rInt == &intOne:"<<&rInt<<endl;//C++不提供访问引用本身地址的方法,因为其没有任何意义,故这里的地址和目标本身intOne的地址相同。
    return 0;
}

运行结果:

intOne:5

rInt:5

&rInt == &intOne:00F3:5300

引用一旦初始化,它就维系在一定的目标上,永远与之绑定,如

int intOne=5;
int& rInt=intOne;
int intTwo=10;
rInt=intTwo;
rInt=8;
cout<<intOne<<","<<intTwo<<endl;//输出8,10

以上代码中,引用 rInt 被重新赋值为 intTwo,但从控制台输出看,引用的绑定关系并没有改变,我们操作 rInt 仍然相当于在对 intOne 进行操作,而不是 intTwo,引用 rInt 的地址仍然与 intOne 一致。

什么可以被引用

可以对变量,指针,对象等进行引用,不能对 void 类型进行引用,也不能对数组进行引用。

void 在语法上相当于一种类型,但本质上并不是一个实际的类型,因为这种类型没有意义,没有任何一个变量或对象的类型是 void,当然也就失去的引用的意义。

我们学习过 C 语言将知道,数组名本质是数组的首地址,是一个 const 型的指针,如果我们要对一个数组进行引用,那么将意味着数组中的每一个元素都要初始化为其他的内存实体,显然不现实;另一方面,数组名代表的是整个数组空间的起始地址,如果对其引用,那将和指向数组的指针没有多少区别。

以下均为错误行为

void& a=3; //error
int a[10];
int& ra[10]=a; //error
int num=5;
int&& rNum=num;//error无引用的引用,二级引用?
int& *p= &num ;//error无引用的指针
int& r= null;//无意义
int& ri=int;//引用是对变量或对象的引用,而不是对一种类型的引用

用引用传参

以前我们想通过函数对变量进行处理,但我们发现,变量(实参)传入函数后,函数会将实参赋值给形参,然后对形参进行函数操作,最终我们的实参被原封不动的“还了回来”,之前我们通常用变量的指针进行处理,而现在我们多了一种手段:引用

void swap(int& a,int& b)
{
    int temp=a;
    a=b;
    b=temp;
}
int main(){
    int x=5,y=10;
    cout<<"before:"<<x<<","<<y<<endl;//输出before:5,10
    swap(x,y);
    cout<<"after:"<<x<<","<<y<<endl;//输出before:10,5
    return 0;
}

引用具有指针的特性,但在调用引用传递的函数时,可读性比指针传递更好,简单清晰。

函数返回多个值

众所周知,函数只能返回一个值,如果需要返回多个值该怎么办?解决办法之一就是用引用给函数传递你需要返回的参数,以下程序片段实现了函数返回多值

bool Factor(int,int&,int&);
int main(){
    //..
    Factor(num,Squared,Cubed);//Squared和Cubed即为函数返回的另外两个值
    //..输出Squared和Cubed
    //..
}
bool Factor(int n,int& rSquared,int& rCubed){
if(n>20||n<0)
    return true;
rSquared =n*n;
rCubed=n*n*n;
return false;
}

程序需要的 Squared 和 Cubed 是通过改变传递给函数的引用 rSquared 和 rCubed 返回的,而没有使用函数本身返回的 bool 值。

用引用返回值

函数返回值时,需要生成一个值的副本;用引用返回值时,不生成副本。

float func1(float r){
//..
}
float& func2(float r){
//..
}
int main(){
    float a=func1(5.0);
    float& b=func2(5.0);
    float c=fun2(5.0);
//..
}

调用 func1 时,函数返回值先经过栈区的临时变量,在传递给 main 函数中的变量 a;b 调用 func2 时,函数返回值直接作为引用 b 的初始化,不经过栈区创建临时变量,c 调用 func2 时,直接将函数返回值传递给 c 变量,不经过栈区临时变量。

func2 ()函数返回一个引用,因此不产生任何返回值的副本,当然,这个返回值需要使用全局变量或静态变量,避免函数结束后,该变量被释放。

略...

函数作为可修改的左值*

思路:让函数返回一个引用(通过引用传入函数,或全局变量等...)然后就可以对函数所返回的引用进行操作了,此时函数即为一个可修改的左值。

const 限定引用?

C++ 不区分变量的 const 引用和 const 变量的引用,程序不能给引用本身重新赋值,前面我们已经提到,因此引用总是 const,如果对引用进行 const 那么等价于使所引用的对象成为 const 型变量。

以下为错误的引用声明

const double const& a=1;//error

编辑:Henry 2021-03-03 未授权禁止转载


Archives QR Code
QR Code for this page
Tipping QR Code