C++ 引用(详解引用返回)

一、引用的引入

为什么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.引用返回可以做左值使用!也就是函数调用可以作为赋值语句的左边。

你可能感兴趣的:(C++,c++)