• 定义
  • 应用
  • 存在对指针取引用
  • 不存在对引用取地址
  • 存在指针的指针,不存在引用的引用
  • 存在指针数组,不存在引用数组
  • 数组的引用
  • 常引用
  • 常引用的特性
  • 临时对象的常引用
    • 类型不同的变量常引用本质剖析
  • 在能够使用 const 的地方就使用 cosnt
  • 引用的本质
    • 引用的大小
    • 引用的类型
    • 结论
    • 反汇编比对指针和引用
      • 源代码
      • 汇编代码比对结果
      • 结论

定义

变量名本身是一段内存的引用,也就是别名。
引用是为已有变量起别名。

int a;
int &ra = a;

引用是声明关系,不分配内存空间(宏观)。
引用必须初始化,不能独立存在。
与被别名的变量具有相同数据类型。

代码演示:

#include <iostream>using namespace std;int main()
{int a = 100;int& ra = a;cout << "a = " << a << endl;cout << "ra = " << ra << endl;cout << "&a = " << &a << endl;cout << "&ra = " << &ra << endl;cout << "sizeof(a)= " << sizeof(a) << endl;cout << "sizeof(ra) = " << sizeof(ra) << endl;return 0;
}

运行结果:

值相等,地址相等,大小相等,证明了引用在内存中的别名关系。

可以对引用再次取引用,对一个变量建立多个引用,多个引用之间是等价关系。
代码演示:

#include <iostream>using namespace std;int main()
{int a = 100;int& ra = a;int& rb = a;int& rc = rb;int& rd = rc;cout << "a =  " << a << endl;cout << "ra = " << ra << endl;cout << "rb = " << rb << endl;cout << "rc = " << rc << endl;cout << "rd = " << rd << endl;cout << "&a =  " << &a << endl;cout << "&ra = " << &ra << endl;cout << "&rb = " << &rb << endl;cout << "&rc = " << &rc << endl;cout << "&rd = " << &rd << endl;cout << "sizeof(a)  = " << sizeof(a) << endl;cout << "sizeof(ra) = " << sizeof(ra) << endl;cout << "sizeof(rb) = " << sizeof(rb) << endl;cout << "sizeof(rc) = " << sizeof(rc) << endl;cout << "sizeof(rd) = " << sizeof(rd) << endl;return 0;
}

运行结果:

应用

取代指针传参。
C++可以用引用解决的问题,避免用指针来解决。

代码演示;

#include <iostream>using namespace std;void swapByValue(int a, int b)
{int tmp;tmp = a;a = b;b = tmp;
}void swapByPtr(int* a, int* b)
{int tmp;tmp = *a;*a = *b;*b = tmp;
}void swapByRef(int& a, int& b)
{int tmp;tmp = a;a = b;b = tmp;
}int main()
{int a = 3, b = 5;cout << "a = " << a << " b = " << b << endl;swapByRef(a, b);cout << "a = " << a << " b = " << b << endl;return 0;
}

运行结果:

引用的从宏观上可以理解为:扩展了变量的作用域,传参后,就像在本地解决问题一样。
把一个变量以引用的方式传到另一个作用域,等价于扩展了该变量的作用域。
避免了传 n 级指针,解决 n-1 级指针的问题,即平级内解决问题。

存在对指针取引用

代码演示:

#include <iostream>
using namespace std;void swapByRef(char * & a, char * & b)
{char * tmp;tmp = a;a = b;b = tmp;
}int main()
{char* p = "hello";char* q = "world";cout << "p = " << p << " q = " << q << endl;swapByRef(p, q);cout << "p = " << p << " q = " << q << endl;return 0;
}

运行结果:

不存在对引用取地址

引用的本质:对指针的包装,避免使用裸露的指针。
设计思想:C++避免对引用再次拆封。
代码演示:

#include <iostream>
using namespace std;int main()
{int a;int* p = &a;int* & pr = p;int& ra = a;int& * rpa = &ra;return 0;
}

编译器报错:不允许使用指向引用的指针。

存在指针的指针,不存在引用的引用

指针的指针,即二级指针。
C++为了避免 C 语言设计指针的"失误",避免了引用的引用这种情况,也避免了引用的引用的引用的…的引用的情况。
这种可穷递归的设计本身就是有问题的。

代码演示:存在指针的指针

#include <iostream>
using namespace std;int main()
{int a;int* p = &a;int** pp = &p;int*** ppp = &pp;int**** pppp = &ppp;//无穷无尽return 0;
}

代码演示:不存在引用的引用

#include <iostream>
using namespace std;int main()
{int a;int & p = a;int&& pp = p; //刹车return 0;
}

存在指针数组,不存在引用数组

数组名,本身是首元素的地址,若首元素是引用的话,数组名就成了引用的指针,与上面说过的不符,即不存在引用的指针。
代码演示:存在指针数组

#include <iostream>
using namespace std;int main()
{int a, b, c;int* pArr[] = {&a, &b ,&c};return 0;
}

pArr 代表首元素地址,首元素是 &a 指针,则 pArr 是二级指针。

代码演示:不存在引用数组

#include <iostream>
using namespace std;int main()
{int a, b, c;int & pArr[] = {a, b ,c};return 0;
}

编译器报错:

pArr 代表首元素地址,首元素是变量名a(可以将a理解为对内存的引用),上面说过不允许对引用取地址。

数组的引用

代码演示:

#include <iostream>
using namespace std;int main()
{//数组名的两重性://1:代表整个数组。//2:代表首元素地址。int array[5] = {1,2,3,4,5};int* const & pr = array;     //int* const &cout << pr << endl;cout << array << endl;cout << "sizeof(pr) = " << sizeof(pr) << endl;cout << "sizeof(array) = " << sizeof(array) << endl;for (int i = 0; i < 5; i++){cout << pr[i];}cout << endl;int(&ra)[5] = array;cout << ra << endl;cout << array << endl;cout << "sizeof(ra) = " << sizeof(ra) << endl;cout << "sizeof(array) = " << sizeof(array) << endl;for (int i = 0; i < 5; i++){cout << ra[i];}cout << endl;return 0;
}

运行结果:

常引用

C++中 const 定义的变量称为常变量。
const 修饰的变量,有着变量的形式,常量的作用,用作常量,常用于取代#define 定义的宏常量。
#define 宏定义在预处理阶段替换,const 常量在汇编阶段替换。

常引用的特性

const 的本意,即不可修改。所以,const 对象,只能声明为 const 引用,使其语义保持一致性。

no-const 对象,既可以声明为 const 引用,也可以声明为 no-const 引用。
声明为 const 引用,则不可以通过 const 引用修改数据。

代码演示:

#include <iostream>
using namespace std;
int main()
{const int val = 10;//int& rv = val; //err类型不等价const int &rv2 = val;//类型等价int data = 666;int& rd = data;const int& rd2 = data;//非const 对象生命为 const 引用//rd2 = 333;    不可修改cout << "data = " << data << " rd = " << rd << " rd2 = " << rd2 << endl;data = 999;                                      cout << "data = " << data << " rd = " << rd << " rd2 = " << rd2 << endl;return 0;
}

运行结果:

临时对象的常引用

临时对象:不可以取地址的对象。

临时对象:

  1. CPU中计算产生的中间变量。
  2. 常量。
  3. 表达式。
  4. 函数返回值。
  5. 类型不同的变量。

代码演示:临时对象的常引用

#include <iostream>using namespace std;//临时变量  即不可取地址的对象int foo()
{int a = 66;return a;
}int main()
{//常量const int& cc = 55;cout << "cc = " << cc << endl;//表达式int a = 3;int b = 5;const int& ret = a + b;cout << "ret = " << ret << endl;//函数返回值const int& ra = foo();cout << "ra = " << ra << endl;//类型不同的变量double d = 100.12;const int& rd = d;cout << "d = " << d << endl;cout << "rd = " << rd << endl;return 0;
}

运行结果:

临时对象的常引用本质:产生中间变量。

类型不同的变量常引用本质剖析

代码演示:

#include <iostream>using namespace std;int main()
{double d = 3.14;//int & t = d;    err 类型不等价const int& rd = d;   //产生中间变量cout << "d = " << d << endl;cout << "rd = " << rd << endl;d = 4.14;cout << "d = " << d << endl;cout << "rd = " << rd << endl;return 0;
}

运行结果:

本质上 const 引用,引用了一个不可改变的临时变量,

const int tmp = data;
const int & rd = tmp;

此时,我们改变了 data 的值,临时变量 tmp 的值并没有发生改变。

在能够使用 const 的地方就使用 cosnt

好处:

  1. 避免无意修改数据的编程错误。
  2. 使用 const 处理 const 和 非cosnt 。否则将只接受 非const数据。
  3. 使用 cosnt引用,可使函数能够正确的生成并使用临时变量。(实参与引用参数不匹配,就会产生临时变量。)

引用的本质

引用的本质:C++对指针的包装,引用即指针。

引用的大小

代码演示;

#include <iostream>using namespace std;struct TypeP
{char* p;
};struct TypeC
{char c;
};struct TypeR
{char& r;
};int main()
{cout << "sizeof(TypeP) = " << sizeof(TypeP) << endl;cout << "sizeof(TypeC) = " << sizeof(TypeC) << endl;cout << "sizeof(TypeR) = " << sizeof(TypeR) << endl;return 0;
}

运行结果:

引用的类型

C++中只有 const 类型的数据,要求必须初始化。
引用也必须要初始化,所以引用是 const 修饰的指针,一经声明,不可修改。引用的内容可以修改。所以是:type* const p

结论

引用的本质是 const 类型的指针,即 type* const p
引用是对指针的封装。
从微观角度来说,引用至少需要分配一个指针类型大小的内存空间。

反汇编比对指针和引用

源代码

代码演示:

#include <iostream>using namespace std;void swapPtr(int* p, int* q)
{int t = *p;*p = *q;*q = t;
}
void swapRef(int& p, int& q)
{int t = p;p = q;q = t;
}
int main()
{int a = 3; int b = 5;swapRef(a, b);swapPtr(&a, &b);return 0;
}

汇编代码比对结果

结论

对同一个功能相同的程序,分别采用了指针和引用的两种方式来进行编写,汇编得到的结果一致。
证明:引用的本质是对指针的封装。

想和高手侃侃而谈C++引用?看这一篇就够了【C++引用】相关推荐

  1. Pyecharts1.x版本全网最全教程,想学数据可视化的,看这一篇就够了!

    前言 本项目整理了目前pyecharts支持的所有图表以及基础配置项- 所有代码均基于Pyecharts v1.7.1版本,均已全部运行通过: 文中代码是基于jupyter notebook中写的,如 ...

  2. 运维学python用不上_作为运维你还在想要不要学Python,看完这篇文章再说!

    原标题:作为运维你还在想要不要学Python,看完这篇文章再说! 本文由马哥教育Python自动化实战班5期学员推荐,转载自简书,作者为Li.Yingjie,内容略经小编改编和加工,观点跟作者无关,最 ...

  3. 云小课|想实现资源全自动备份?看完这篇秘籍,不再蕉绿~

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:在给备份系统设置& ...

  4. docker 删除所有镜像_关于 Docker 镜像的操作,看完这篇就够啦 !(下)| 文末福利...

    紧接着上篇<关于 Docker 镜像的操作,看完这篇就够啦 !(上)>,奉上下篇 !!! 镜像作为 Docker 三大核心概念中最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌 ...

  5. 聊聊Java8之后的JDK升级内容(看这一篇就够了)

    聊聊Java8之后的JDK升级内容(看这一篇就够了) 背景 从 JDK 8 到 JDK 17 的新特性 JDK8 回顾 JDK9 JDK10 JDK11 JDK12 JDK13 JDK14 JDK15 ...

  6. 技术交底书怎么撰写?看这一篇就够了

    文章目录 技术交底书怎么撰写?看这一篇就够了 专利技术交底书格式 1. 发明(或实用新型 以下同)的名称 2. 技术领域 3. 背景技术 4. 发明内容 5. 附图说明 6. 具体实施方式 技术交底书 ...

  7. Fortran保姆级教学——考试所有知识点看这一篇就够了

    Fortran保姆级教学--考试所有知识点看这一篇就够了 临近期末本人复习的同时将整个fortran课堂知识整理了下来,希望学弟学妹们今后学这门课的时候不至于在csdn找不到系统的教程,也希望能帮到需 ...

  8. 17万字 JUC 看这一篇就够了(三) (精华)

    今天我们继续来学习Java并发编程 Juc框架 ,把剩余部分学习完 17万字 JUC 看这一篇就够了(一) (精华) 17万字 JUC 看这一篇就够了(二) (精华) 文章目录 非公原理 加锁 解锁 ...

  9. serviceloader java_【java编程】ServiceLoader使用看这一篇就够了

    转载:https://www.jianshu.com/p/7601ba434ff4 想必大家多多少少听过spi,具体的解释我就不多说了.但是它具体是怎么实现的呢?它的原理是什么呢?下面我就围绕这两个问 ...

  10. 深度好文:云网络丢包故障定位,看这一篇就够了~

    深度好文:云网络丢包故障定位,看这一篇就够了~ https://mp.weixin.qq.com/s/-Q1AkxUr9xzGKwUMV-FQhQ Alex 高效运维 今天 来源:本文经授权转自公众号 ...

最新文章

  1. 解题报告(一)B、(CF453D) Little Pony and Elements of Harmony(FWT经典套路 + 任意模数 k 进制FWT + 快速幂)(2)
  2. UIActivityViewController: LaunchServices: invalidationHandler called
  3. tensorrt 低精度推理
  4. Matlab 条形图实例
  5. 终于知道PUBWIN2009的数据库用户名与密码已经成功连接
  6. uc的剪切板能关掉吗_创意手工 | 一张纸折出专属礼品袋,漂亮简单还实用!你爱了吗?!...
  7. 大数据及hadooop简介
  8. hibernate - Transaction not successfully started
  9. 探究position定位中absolute和relative的异同
  10. 放大分析双缓冲类时间计算问题
  11. 记录一次es商品模糊查询
  12. 基于WEB的自行车租赁管理系统设计与实现
  13. 【MySQL】轻松学习 唯一索引
  14. Elasticsearch 6.4 ingest-attachment对office文件IK分词器全文检索(1) HttpAPI使用
  15. android 美团下拉菜单,Android仿美团分类下拉菜单实例代码
  16. 方舟搭建服务器显示mod出错,为什么我方舟进不去mod服务器 | 手游网游页游攻略大全...
  17. gcc -c -o编译过程
  18. 利用阿里云搭建NFS服务器
  19. 【2020年第七次人口普查】省市县三级人口婚姻状况和妇女生育状况
  20. widget中自动横竖屏切换时的问题

热门文章

  1. 实验1 LINUX基本操作
  2. [密码学] 密钥分发
  3. 简述http请求中的同步和异步
  4. Android11有哪些vts
  5. 2021-09-22
  6. 2020-11-1(xml)
  7. 『安全漏洞』Windows 云同步引擎API整数溢出漏洞
  8. 为修复一个代码执行安全漏洞,TensorFlow决定不再支持YAML
  9. 012 背包二叉树遍历分析和代码编写
  10. 用户层和内核层异常的处理流程