谈谈引用吧

什么是引用:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会 为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 类型& 引用变量名(对象名) = 引用实体; 

什么时候用引用比较合适呢?

1.引用做参数

clude <iostream>
using namespace std;
void Swap1(int a,int b)
{
        int tmp=a;
        a=b;
        b=tmp;
}
void Swap2(int *l,int *r)
{
        int tmp=*l;
        *l=*r;
        *r=tmp;
}

void Swap3(int&l,int&r)
{
        int tmp=l;
        l=r;
        r=tmp;
}

int main ()
{
        int  a=0,b=1;
        cout<<a<<b<<endl;

        Swap1(a,b);
        cout<<a<<b<<endl;

        Swap2(&a,&b);
        cout<<a<<b<<endl;

        Swap3(a,b);
        cout<<a<<b<<endl;
        return 0;
}

引用和指针都可以将两数交换。因为引用就是别名所以可以改变。

另外,请大家阅览下面代码

#include <iostream>
using namespace std;
typedef struct  Big
{
        int a[10000];
}Big


void Func(Big  b)
{

}
int main ()
{
        Big  big;
        Func(big);
        return 0;

}

虽然这段代码没有错但是这段代码是有一个很大的缺陷的。参数传入时要产生一个很大的临时变量。

我们可以用以下方式解决。

#include <iostream>
using namespace std;
typedef struct  Big
{
        int a[10000];
}Big


void Func(Big  b)
{

}
int main ()
{
        Big  big;
        Func(big);
        return 0;

}
#include <iostream>
using namespace std;
typedef struct  Big
{
        int a[10000];
}Big;


void Func(Big&  b)
{

}
int main ()
{
        Big  big;
        Func(big);
        return 0;

}

这两种方法就可以解决前面的问题了。但又有新问题出现了。不一定所有传入的参数都是可以改的,但如果按以上的传参方法,大家可以看出因为传入的是别名所以可以任意修改,这是我们应该用起const关键字,写成   void   Func(const  Big&  b)就可以了。如果有朋友对const关键字感兴趣,可以戳链接https://blog.csdn.net/a15929748502/article/details/81195121
    2.引用做返回值

请大家看下面的代码

#include <iostream>
using namespace std;


int Add(int a,int b)
{
        int c=a+b;
        return c;
}

int main ()
{
        int &ret=Add(1,2);
}

编译一下。可以看到报错,错误原因是类型不匹配

我们来分析一下,为神魔及引用不过呢,原来C这个变量的生命周期在函数中,C属于Add(int a ,int b )这个函数栈帧。说一说函数结束时C也销毁了,所以说也生成了一个临时变量,这个临时变量不可以改的。所可以如下改

#include <iostream>
using namespace std;


int Add(int a,int b)
{
        int c=a+b;
        return c;
}

int main ()
{
        const int &ret=Add(1,2);
}

这样就可以通过编译了,可这种方法看起来怪怪的,怎杨才可以让它看起来不怪呢,我们可以这样写,

#include <iostream>
using namespace std;


int& Add(int a,int b)
{
        int c=a+b;
        return c;
}

int main ()
{
        int& ret=Add(1,2);
}

编译一下,可以看到报出警告,但还是编译的过去的。这是把C的别名付给了ret,所以这时不加const就是可以的。但是又有新问题产生了。在这里我要把代码做一个小小的改动,改动如下。

#include <iostream>
using namespace std;


int& Add(int a,int b)
{
        int c=a+b;
        return c;
}

int main ()
{
        int& ret=Add(1,2);
        Add(10,20);
        cout<<ret<<endl;
        return 0;
}

编译一下

可以看到在我们并没有修改ret 值得时候ret 的值被修改成30,这就有了问题,这个问题是怎样产生的呢,我们又该怎样避免。

下面我们来分析一下为神魔没有修改ret 值得时候ret 的值被修改为30;我们可以知道我们返回的其实是c的别名的别名,也就是c的别名。但c是在函数栈帧中创建的,也应在函数栈帧中消毁,也就是说函数结束时C就已经不存在了,那么ret作为他的别名,也就很没有安全性,因为我们其实用的是一块没有给我们授权的空间。

我们搞清楚了原因,接下来我们就要解决这个方法了。

神魔时候可以用引用返回呢?;出了作用域函数还在时 ,就可以用引用来接受

也就是说一定不要返回一个临时变量的引用

3.引用与指针的区别

1).概念中语法上引用时是不开辟空间的,但是指针是要开辟四个字节的空间来存储指针的

但是实际上引用与指针的底层是一样的,有兴趣的朋友可以查阅汇编代码。

2.引用在定义时必须初始化,指针没有要求 一旦一个引用被初始化为指向一个对象,就不能再指向其他对 象,而指针可以在任何时候指向任何一个同类型对象

3.没有NULL引用,但有NULL指针

4.在sizeof中含义不同:引用结果为引用类型的大小,但指针始 终是地址*空间所占字节个数

5.引用自加改变变量的内容,指针自加改变了指针指向6.

有多级指针,但是没有多级引用 指针需要手动寻址,

7.引用通过编译器实现寻址 引用比指针使用起来相对更安全 

猜你喜欢

转载自blog.csdn.net/a15929748502/article/details/81195257