[C++]什么是引用,以及引用和指针的关系(对内存和指针运用的理解)

我看到网上,有很多所谓的,引用是引用变量,指针是指针变量,
对某个变量起了个别名之类的错误言论.
百度百科都是说引用是变量的别名,这是误人子弟!
以下是百度百科原文

引用(reference)就是C++对C语言的重要扩充。引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符
&引用名=目标变量名;

如果想方便他人理解,这么说,还可以让他人认同.
但是言之凿凿的说引用和指针是两个类型,那么就太可笑了
.

什么是引用?
引用其实不过是指针更方便的写法罢了.
不过又为了不让C++过于隐晦和繁琐,对其加上了限制,比如不允许二次引用.

可能有的人,觉得不信,因为可能上学的时候,就被老师教育,引用是个新变量类型,或者说,是变量别名.
但我想说的是,这些都是错误的!

那么如何证明这一点呢?

很简单,我们写一段代码就知道了.

void AddReferen(int&a, int&b)
{
    a+=b;
}

void AddPointer(int*a,int*b)
{
    *a+=*b;
}

这是两个函数,上面的是以引用作为参数,而下面的,则是以指针作为参数传递
引用和指针在汇编层面是一样的

大家可以明显的看到,哪有什么引用参数,在汇编层面上,都是以指针来传递的.
除了两个函数的地址以为,它们连一丝一毫的不同都没有.
在编译器看来,这就是两个一样的函数.
如果以release模式编译,大家可以大胆的猜一猜,我们还会有这两个函数了么?
很显然,只会剩下一个函数地址.

不过这么简单的函数,一般的编译器会直接替换掉.

现在我们重新写一段代码,这次我用VisualStudio来展示.

#include <iostream>

struct RefeAddress
{
    int& reference; // 引用的地址会被编译器优化掉,而结构体必须存在地址,这是硬性规定,只有这样可以避免引用地址被优化.
    RefeAddress(int varA) :reference(varA){}
};

int main(void)
{
    int varA{ 1 };
    RefeAddress ref{ varA };// 给引用初始化                      
    std::cout << "变量A的地址:\t" << &varA << std::endl;
    std::cout << "引用的地址:\t" << &ref.reference << std::endl;
    std::cout << "Refe对象的地址:\t" << &ref << std::endl; 
    return 0;
}

在这里插入图片描述

引用存在自己的地址,因为是指针类型,所以在32程序是4字节.
只不过只有结构体硬性要求内存对其,所以在结构体里面声明的变量地址不会被优化掉.
记住一点,所有的局部变量都可以没有地址,这取决于编译器的决定

引用赋值和指针赋值
用32位的汇编代码,方便各位容易理解.
可以看到

006017A3  mov         eax,dword ptr [ref]  
006017A6  mov         ecx,dword ptr [numberA]  
006017A9  mov         dword ptr [eax],ecx  

006017AB  mov         eax,dword ptr [intP]  
006017AE  mov         ecx,dword ptr [numberA]  
006017B1  mov         dword ptr [eax],ecx  

和之前的函数一样,实现都是靠ptr来实现的.
这都证明了,引用就是指针.
既然引用就是指针,那么我们为什么需要要到引用呢?
很简单的道理.
因为这样写,很爽,可以让程序员的双手,减少离开a`z的主键区.


运用小帮助
如果你有一个函数,类似以下

int& Number(int &var)
{
    return var;
}

你需要这个函数的返回值赋值给相同类型的指针.
只要在这个函数前加&取地址符,来进行变量升级操作即可
因为引用虽然也是指针,但是它会返回值,而不是地址.


#include <iostream>

int& Number(int &var)
{
    return var;
}

int main(void)
{
    auto  var  {Number(*new int { 0 })};
    auto* intP {&Number(*new int{ 1 })};
    std::cout << var << "|" << *intP << std::endl;
    return 0;
}

如果你能明确的理解下面这行代码,那么证明你在内存层面的认知,是很不错的.
你已经可以灵活的去运用一级指针了

 auto* intP {&Number(*new int{ 1 })};

我们先来分析&Number这个函数,Number函数的返回值类型是引用,所以它会返回地址中的值.
而指针可不认你地址中的值,它只认地址.
所以我们需要对这个值,进行升级操作,也就是取地址&,得到一级指针. 这样intP就可以被赋值了.

再来看分析*new int{1}这一段.
Number函数的参数1,是个int引用,所以它不认地址,只认值.
而new的返回值,则是个一级指针,所以我们需要用 * 来将其降级操作.
取地址中的值给它.
然后它再靠这个值,取地址,给自己.
听起来很绕,但在汇编代码中,这不会有任何的效率影响,大家都是只认地址的.


这一章就没有代码下载啦.
但是也可以去github上下载我其他的代码
https://github.com/Babaoxianyu/BlogSpotSource
配合博客上的文章,快乐理解C++的一些知识点.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八宝咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值