C++中新增了引用类型,所以函数的返回值可以是引用类型。那么就会有人想问 返回引用类型与返回非引用类型有区别吗?
结论是显然的,而且有明显的区别。尤其初学者会很容易绕进去。让我们先看四个函数原型。以int类型来举例
(1) int fun(...)
{
return ....//后面跟的是一个引用
}
例如:int fun(int &a)
{
return a;
}
(2)int fun(...)
{
return....//后面跟的是一个非引用
}
例如:int fun(int a)
{
return a;
}
(3)int& fun(...)
{
return....//后面跟的是一个引用
}
(4)int& fun(...)
{
return....//后面跟的是一个非引用
}
上面四种函数,(1)(2)是返回非引用类型的函数,(3)(4)是返回引用类型的函数。对于返回的是哪种类型的函数,我们要看函数名前面的参数类型,而不是函数体内return后的类型,这点切记!!!
一、C++规定当函数返回的是非引用类型时,函数会创建临时对象(temporary object),函数返回的就是这个临时对象。在求解表达式时,如果需要一个地方存储其运算结果,编译器会创建一个没有命名的对象,这就是临时对象。浅显的说,当你调用了函数,函数会 return一个值 那么这个值总得有存放的地方吧,编译器就把会把值存放在一个没有命名法临时对象中。
看一个简单的程序
对应于(2)
#include<iostream>
int fun(int &a)
{
int b=a;
return b;
}
int main()
{
int a=8;
int b=fun(a);//***
return 0;
}
int b=fun(a);分析此行代码:因为fun是返回非引用函数,调用fun函数,函数体内执行return时,需要创建临时变量temp,相当于执行了 int temp;然后把return的值赋值给temp,相当于执行了temp =b;然后用temp的值初始化b,相当于执行了int b=temp。
int b=fun(a);等加于int temp;temp=b;int b=temp;
当此表达式结束后 temp会消亡,所以不能int& b=fun(a); temp是在fun中的局部变量,fun调用完,表达式结束后,temp消亡,b引用的变量temp不存在了,所以编译不会通过。
对应于(1)
#include<iostream>
int fun(int &a)
{
return a;
}
int main()
{
int a=8;
int b=fun(a);//***
return 0;
}
int b=fun(a);分析此行代码:同上,等同于int temp;temp=a//用a引用的变量的值赋值给temp;int b=temp//用temp初始化b,当表达式结束后,temp会消亡。
二、C++规定当函数返回的是引用类型时。C++primer 上说当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。
//find longer of two strings
const string &shorterString(const string &s1,const string &s2)
{
return s1.size()<s2.size()?s1:s2;
}//行参和返回类型都是指向const string对象的引用,调用函数和返回结果时,都没有复制这些string对象。
例如下面函数,请分析:
int a;
int& fun()
{
return a;
}//因为a是全局变量,函数的返回值是a本身,a具有全局作用域。假如a是函数内的局部变量,则函数会出错。
按照C++primer的说法 返回的是a这个全剧变量本身。为了跟返回非引用函数的统一,我本人理解返回的是对全局变量的引用即int b=fun(a);我理解为int &temp=a;int b=temp。可能这样理解有点牵强。函数返回的是引用,引用就是变量的别名,可以等同于初化它的对象,引用=变量(初始化引用的变量),所以函数返回的就算a变量本身。
int a;
int& fun()
{
int &b=a;
return b;
}//a的别名b,但是这个别名只能在fun函数体内使用,出了fun函数体就会消亡,函数返回值是引用,那么返回的其实就是a这个变量!!!
千万不要返回局部对象的引用
int &fun(int &a)
{
int b=a;
return b;
}
此函数运行会出错,因为它返回了局部对象的引用。当函数执行完毕,int b占用的存储空间会被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。
确保返回引用安全的一个好方法是:请自问,这个引用指向哪个在此之前存在的对象?
三、把返回引用以及非引用的函数赋值给其他变量
函数返回值(int Func1())时,要产生一个临时变量作为函数返回值的副本(保存该函数调用中要返回的值),而用引用返回值 (int &Func2())时,不产生值的副本。故在用函数返回值定义一个引用(int &ia = Func1())时,该引用为临 时变量的引用,由于临时变量作用域短暂,故该引用存在随时无效的危险,是不合法的。而用引用返回值时,由于不产生值的副本,故 int &i = func2();在func2()的返回值是一个静态或者全局变量的情况下的调用是合法可行的,其直接用全局数据区中的变量来 初始化引用i,当然如果Func2中的返回值是局部变量,那么当然是非法的。
不妨自己再分析一下下面的四种函数调用:
条件:
int Func1();//假设是合法函数
int &Func2();//假设是合法函数
情况:
int &i = Func2();//引用i引用的是与一个变量,这个变量作用域大于等于int &i,合法
int &ia = Func1();//引用ia引用的是临时变量,不合法
int ib = Func1();//临时变量初始化ib,合法
int ic = Func2();//Func2返回的对象(变量)本身初始化ic;
记得这好像是钱能的那本C++教程里面的题目,应该没有记错。