一、引用的引入
为什么C++中有引用这个概念?
因为指针随意访问内存空间,会非法读取未授权的内存空间,有很大的风险。
引用是为了利用指针的优点,又避免访问非授权的内存范围而引入的。
因此,引用采用改名的机制,将一个变量赋予多个名字,每个名字只能访问自己的内存空间
二、引用的定义
1.引用的定义
int a = 0;
int &ra = a; //这里定义了变量a的别名ra, ra即是变量a的另一个称呼,共同操控同一个内存空间
注意:ra不是变量,且引用必须立即关联
int &ra = a; 在编译器下等同于以下两句代码
int* @sysp=&a; //系统自定义一个临时指针变量@sysp(@表示这是系统内部定义的)
define ra (*@sysp) //这里是一个宏定义,即ra是一个宏名,不是变量
2.引用的条件
由此句int* @sysp=&a; 可知,系统内部定义了一个指针,取右值地址,所以定义引用的右端必须是可被取地址的。
即不是任意表达式和任意变量都可以定义引用来关联
例:
int a;
int &ra = ++a; // int *@sysp = &(++a) 这里++a本质上是改变之后的a,可以被引用
//int &ra = a++; // 后自增不能充当左值表达式,不可以被引用
const int i = 0; // const修饰i为常量变量 不可改变
int &ra = i; // int *@sysp = &i i为常变量 不可取地址
结论:能够充当左值的表达式和能够充当左值的变量,能给定义引用关联
即能够充当左值的表达式和变量,能作为引用的右值
三、引用的返回
引用返回指的是:函数的返回值是引用类型如:int& f() {};
由值传递可知,函数的返回实际上是return给系统的一个临时变量;那函数若返回引用类型,则return的必须是能够充当左值的表达式/变量。
具体情况具体分析,以下给出不同情况的代码:
1.引用关联函数
//1.引用关联函数
double tmp = 0; //定义一个全局变量tmp
double func1(double r)
{
tmp = r*r; //赋给全局变量
return tmp; //double @sysT = tmp;
}
double func2(double r)
{
double temp = r*r; //定义局部变量temp
return temp; //double @sysT = tmp;
}
void main()
{
//错误
double &a = func1(5.0); //double &a = @sysT; 此处a引用关联的是系统临时变量@syst(@syst复制了全局变量tmp的值) 函数结束时临时变量@syst自动销毁;
//错误
double &b = func2(5.0); //double &b = @sysT; 此处a引用关联的是系统临时变量@syst(@syst复制了局部变量temp的值) 函数结束时临时变量@syst自动销毁;
可见,主函数引用关联函数关联的是系统临时变量,函数结束时会自动销毁,不可引用,报错。
2.函数返回引用类型
double tmp = 0;
double& func3(double r)
{
tmp = r*r;
//return r*r; //错误 double &@sysR = r*r; 不可直接return r*r (r*r)为常量,不可取地址
return tmp; //double &@sysR = tmp;
}
double& func4(double r)
{
double temp = r*r; //定义局部变量temp
return temp; //double &@sysR = temp;
}//temp.~ 局部变量 函数结束时自动析构销毁
int main()
{
//成功
double c = func3(5.0); //double c = @sysR; @sysR引用关联了tmp,即d复制了tmp
//警告
double d = func4(5.0); //double d = @sysR; d想引用@sysR,又因为@sysR引用temp,即d复制了temp;但temp为局部变量,函数结束会自动销毁,可能会错误,若内部迅速拷贝,不会后面造成严重后果
//错误
double &e = func4(5.0); //double &e = @sysR; 一定错误,e想引用@sysR,而@sysR引用了temp,引用的引用,即e引用temp,但temp是局部变量,已经归还内存了。
//成功
double &f = func3(5.0); //double &f = @sysR; f想引用@sysR,而@sysR引用了tmp,引用的引用,即e引用tmp,temp为全局变量,引用成功
//引用类型的函数做左值 实际上是对tmp赋值
func3(5.0) = 10;//这里是引用类型的函数调用做左值 即对@sysR赋值10(tmp=10)
}
总结:
1.我们应尽力避免出现局部引用——即不要用引用去关联一个生命期短暂的临时变量。
2.引用返回可以做左值使用!也就是函数调用可以作为赋值语句的左边。