C++中的引用

今天整理了一下关于C++中引用的用法

一、简单介绍

观察以下代码

#include <iostream>                                                                                                                 using namespace std;
  int main()
   {
      int a=10;
      int &b=a;
      int &c=a;
      int &d=b;
      cout<<"a:"<<a<<endl<<"b:"<<b<<endl;
     cout<<"c:"<<c<<endl<<"d:"<<d<<endl;
     return 0;
 }   

 

执行结果:

 

这里 b,c,  d 都是对a的引用

注意;引用并不是定义一个变量,而是给一个已知的变量起一个别名,我们可以通过修改

b,c,d,e的值来实现修改a 的值。

引用有以下特点:

1.一个变量可以有多个引用

2.引用必须初始化

3.当已经是一个变量的引用时,不能再成为其他变量的引用

 

当有如下代码时:

int &e=10;

编译器会报错:

我们想用e作为常量10的引用,假设成功了的话,那么我们可以通过e来修改我们的常量10吗?显然常量是不可以修改的。

当我们加上const 之后,

<span style="color:#ff0000">const int &a=10;</span>

a是一个常引用,即左右两边均具有常性,是可以通过的

但我们有以下代码时

int c=10;
float &d=a;

引用时类型不同也会直接报错

看看以下代码:

int a=10;
float b=a;

int c=10;
const float &e=c;

 

上面代码执行中其实是经历了如下过程:

 

这是因为当类型不一致时,我们有借助一个中间的临时变量来完成的

而临时变量时具有常性的,不能被改变的,d其实时临时变量的引用,所以当我们用const 修饰后就符合语法规则

 

二、引用作为参数

1.引用做参数想通过修改内部的值而完成改变外面的值

有如下代码:

 #include <iostream>                                                                                                                 using namespace std;
  void Swap(int &m,int &n)//引用做参数
   {
      int temp=m;
      m=n;
      n=temp;
   }
  int main()
  {
     int a=10;
     intb=20;
     cout<<"a: "<<a<<"  b: "<<b<<endl;
     Swap(a,b);
     cout<<"a: "<<a<<"  b: "<<b<<endl;
     return 0;
 }

 

执行结果;

 

上面的函数完成了两个数的交换,m,n分别是a,b的引用,交换了m,n的值而实现了交换a,b的值。

2.节省空间,提高执行效率

#include <iostream>                                                                                                                        
   using namespace std;
   typedef struct Data
   {
       int array[10000];
    }Data;
 void func(const Data &data)//引用做参数
   {
       //......
   }
   int main()
   {
      Data data;
       func(data);
     return 0;
  }

 

这里函数的参数是一个结构体,如果我们采用值传递,形参也需要开辟一个结构体大小的空间,这样既占用空间还降低执行效率。但是如果采用引用就不会开辟空间。

 

但是这里需要注意,引用作为参数,可以通过修改函数内部的值而改变外面的值,有时,我们并不想让其改变外面的值。就需要传常引用。

三、引用做返回值

(1)值返回

 

#include<iostream>                     
   using namespace std;
    int Add(int a,int b)
    {
       int c=a+b;
       return c;
    }
    int main()
    {
    int &ret=Add(1,2);
       return 0;
    }

 

 

以上代码程序会报错 

其实当函数传值返回时,仍旧是创建了一个临时变量,而且这个变量一般存放在寄存器中,而主函数里的ret则是这个临时变量(具有常性)的引用,那么程序会报错,所以当给ret前面加const修饰时就符合语法规则。

以下为正确形式:

 #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);
       return 0;
   }

 

(二)引用返回

 

 #include<iostream>                                                                                                                  using namespace std;
    int&  Add(int a,int b)
    {
        int c=a+b;
        return c;
    }
    int main()
   {
    int &ret=Add(1,2);return 0;
  }

这段代码虽然可以编译通过,但是会报一个警告

 

 

我们再看一种情况:

 

有点不好理解~

上面Add函数的返回值类型是引用类型,其实可以理解为中间借助一个引用类型(c的引用),而ret是那个引用类型的的引用,从而实现了ret是c的引用,而当函数结束,创建的函数栈帧也释放,c可能是一个随机值,(上述例子中第一次调用Add函数结束后ret仍旧是3,只是因为此处暂时还没有进行其他操做,c还没有被覆盖掉,而当第二次调用Add函数时,创建的是同一块栈帧,c还是之前的位置,ret仍旧是那块位置的引用,所以ret会被修改为30)但此处会有一个警告。

 

 

我们可以看到,与传值返回比较来看,用引用返回时是可以节省空间,但是也存在问题,如上面的例子,但是如果函数调用结束后,返回的这个变量还存在,就可以用引用做返回值。

所以这里有不要随便返回一个临时变量的引用。

可以通过函数代码的汇编看到不同:

 

 

上面可以看到,引用返回时将c的地址保存下来,最后再按照地址来找到c,这种方法与指针的传地址很相似。

而且注意到,这里的出了这个函数c被释放掉了,但是还要去取它的地址,感觉好像是越界访问了。

事实上,越界访问也不一定会报错,例如。

上面这种情况就会报错

 

 

而当我们访问上面这种情况就不会报错。

可以这样解释,一般情况下编译器会设置一些硬件保护,例如

 

 

其实我们从语法上说定义一引用类型是没有开辟空间的,但是从底层汇编来看,引用的实现和指针是一样的。

 

 

 


其实上面的用到引用的地方我们发现引用和指针有很多相似的地方。

例如实现两个数交换,传递的参数是一个很大的结构体时,等等。

总结一下引用和指针的联系和区别:

1.引用只能在定义时初始化一次,之后不能改变,而指针的值是可以改变的

2.引用必须指向有效的变量,而指针可以为空

3.sizeof指针时,是所指变量地址的大小,即指针本身的大小

   sizeof引用时,是所引用变量的大小

4.对指针进行加1或减1操作时,即加或减所指对象的大小,即跨越一个所指对象的大小

  对引用进行加1或减1操作时,即所引用的对象加1或减1.

5.相对来说,引用较指针安全一些,但是指针更加灵活一些。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值