引用

引用的含义

引用表示的给一个变量起一个别名,对引用的操作等同于对变量本身的操作。

引用的用法

因为函数的参数传递只存在 两种方式:

1.值传递

在调用函数时,会替形参在为函数分配的栈区中开辟内存空间并将实参的值拷贝一份给形参,在函数内部对形参的操作并不会影响函数外部实参的值。

2.地址传递

本质上也是值传递,只不过传递的值是地址,所以形参拷贝的值也是地址,虽然形参和实参的地址数据存放的地方不一样但它们是指向同一块内存空间的。所以当函数内部形参指向的内存空间的值发生改变后,实参的值也会相应发生改变。

以前在C语言阶段如果我们想要在函数内部修改函数外部传进来的参数也就是实参的值,必须通过地址传递的方式。


但是在c++中我们多了另一种选择,那就是引用。

1.引用做参数

#include<iostream>
using namespace std;

void swap(int &m,int &n)//使用引用
{
    int temp;
    temp = m;
    m = n;
    n = temp;
}
int main()
{
    int a = 10;
    int b = 20;
    cout << a << " " << b << endl;
    swap(a, b);
    cout << a << " " << b<< endl;
    system("pause");
    return 0;
}

这里写图片描述

从运行结果可以看出:

使用引用作为函数参数,成功在函数内部改变了函数外部的实参的值。


引用做返回值

#include<iostream>
using namespace std;

int &fun(int &n)
{
    return n;
}


int main()
{
    int a = 10;
    cout << a << endl;
    cout << fun(a) << endl;
    fun(a) += 10;
    cout << a << endl;
    system("pause");
    return 0;
}

这里写图片描述
可以看出:

当我做fun(a) += 10;操作时a的值也加了10,因为此时fun(a)返回的是a的引用,对fun(a)操作也就相当于直接对a进行操作。



指针和引用传参的区别

#include<iostream>
using namespace std;

//引用传参
void quote(int &m, int &n)
{

    //打印形参变量的存放地址
    cout << &m <<" "<<&n<< endl;
}
//指针传参
void pointe(int *m,int *n)
{
    //打印形参变量的存放地址
    cout << &m << " " << &n << endl;
}
int main()
{
    int a = 10;
    int b = 20;

    //*********************指针***************************
    cout << "指针传参:" << endl;
    int *p = &a;
    int *q = &b;
    cout << &p << " " << &q << endl;    //打印实参存放地址
    pointe(p, q);                       //打印形参存放地址

    //*********************引用***************************
    cout << "引用传参:" << endl;
    cout << &a << " " << &b << endl;   //打印实参存放地址
    quote(a, b);                     //打印形参存放地址

    system("pause");
    return 0;
}

这里写图片描述

从结果可以看出:

就像上文提到的一样:指针传参,会为形参在栈区开辟一段空间用来存放实参的值(只不过值是地址)。实参和形参是指向同一块内存空间的两个变量;
而引用传递的形参和实参的存放地址是一样的也就是说形参就相当于实参,形参和实参之间的关系就是一个变量的两个名字。


常量引用

从上面我们已经知道,一个变量的引用其实就是给这个变量起了一个别名,编译器并不会单独为其分配空间,那么问题来了,我们都知道常量属于右值,是不能进行取地址操作的,如果我声明一个常量的引用,然后对这个引用做取地址操作会发生什么呢?
#include<iostream>
using namespace std;

int main()
{
    const int &a = 10;
    cout << a << " " << &a << endl;;
    system("pause");
    return 0;
}

这里写图片描述

可以看出:

我们成功地取出了引用的地址,也就是说我们做区地址操作的这个引用并不是存在于常量区。我们可以从反汇编层面看一下是为什么。

    int main()
{
00D75FB0  push        ebp  
00D75FB1  mov         ebp,esp  
00D75FB3  sub         esp,0DCh  
00D75FB9  push        ebx  
00D75FBA  push        esi  
00D75FBB  push        edi  
00D75FBC  lea         edi,[ebp-0DCh]  
00D75FC2  mov         ecx,37h  
00D75FC7  mov         eax,0CCCCCCCCh  
00D75FCC  rep stos    dword ptr es:[edi]  
00D75FCE  mov         eax,dword ptr [__security_cookie (0D7B004h)]  
00D75FD3  xor         eax,ebp  
00D75FD5  mov         dword ptr [ebp-4],eax  
    const int &a = 10;    
00D75FD8  mov         dword ptr [ebp-18h],0Ah  
00D75FDF  lea         eax,[ebp-18h]  
00D75FE2  mov         dword ptr [a],eax  
    cout << a << " " << &a << endl;;
00D75FE5  mov         esi,esp  

注意以下三行汇编指令

00D75FD8 mov dword ptr [ebp-18h],0Ah

00D75FDF lea eax,[ebp-18h]

00D75FE2 mov dword ptr [a],eax

首先在栈上找到ebp-18h偏移的内存双字,然后把十六进制的10存进去,之后再把ebp-18h偏移的内存双字放进eax寄存器,最后把a指向eax中的地址(指向ebp-18h偏移的内存)。
这些操作之后就像相当于:当我们声明一个常量的引用时,会首先在栈区搞个临时变量再把常量的值存在临时变量中,然后再对该临时变量进行引用操作,这也就解释了为什么常量无法取地址而常量的引用却可以取地址。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值