c++|引用

目录

一、引用概念

二、引用特性 

三、常引用 (具有常属性的引用变量)

 四、使用场景


一、引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,他和他引用的变量共用同一块内存空间。

比如:李逵,在家称为“铁牛”,江湖上人称“黑旋风”

那么引用变量的形式是什么

 类型& 引用变量名(对象名) = 引用实体;

#include <iostream>
using namespace std;void TestRef()
{int a = 10;int& ra = a;//定义引用类型,ra仅仅只是a的别名,并没有给ra开空间//注意:在定义引用时,必须给引用变量名初始化--语法规定(祖师爷的规定)printf("%p\n", &a);//打印地址也是没有区别的printf("%p\n", &ra);
}int main()
{TestRef();return 0;
}

 运行结果:

二、引用特性 

1.引用在定义时必须初始化

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

3.引用一旦引用一个实体,再不能引用其他实体(就是只能定义一次嘛)


void TestRef()
{int a = 10;int& ra = a;//定义引用类型,ra仅仅只是a的别名,并没有实质的开空间//注意:在定义引用时,必须给引用变量名初始化,语法规定(祖师爷的规定)//int &ra;//像这样直接定义引用,而不初始化就会报错int& rra = a;//一个变量可以有多个引用,ra和rra都是a的引用printf("%p\n", &a);printf("%p\n", &ra);printf("%p\n", &rra);
}int main()
{TestRef();return 0;
}

运行结果:

三、常引用 (具有常属性的引用变量)

#include <iostream>
using namespace std;void TestRef()
{const int a = 10;//用const修饰变量a,具有常属性,不可直接修改//此时再用int &ra = a;会报错const int& ra = a;//必须加上const修饰才行,为什么,这里有点难理解//来看const int a = 10;和int &ra = a;这两句。a具有常属性,不可直接修改//将具有常属性的a赋值给引用变量,中间其实是会产生一个临时变量,临时变量是自带常属性的,临时变量要赋值给引用变量//而引用变量的类型为int&,引用的实体应该是对应可修改变量的类型,所以将具有常属性的临时变量赋值给可修改类型的引用变量是不可行的。//这就是一个权限放大的过程,是不行的//注意:权限可以平移或者缩小,但不能被放大//那再来看const int a = 10;和 const int& ra = a; a具有常属性,引用变量也具有常属性,可以直接赋值,权限平移const int& aa = 10;//也是权限的平移,10是一个常量,具有常属性,引用变量也是具有常属性//那么再来看权限的缩小int b = 20;const int& rb = b;//b是可修改类型,而生成的临时变量是具有常属性的,引用变量类型也是具有常属性的,所以临时变量可以赋值给引用变量。//即由int类型(可修改类型)b转换成具有常属性的不可修改的临时变量,这是权限的缩小。也是OK的
}int main()
{TestRef();return 0;
}

上面大费周章的说了一下常引用的用法是因为中间产生临时变量 ,那么临时变量是什么,因为什么原因产生的?

答:顾名思义临时变量是一种临时存在的变量,其实临时变量产生的原因是赋值时,两边变量类型的不一致产生的,且自带常属性,它存放在寄存器,由寄存器管理。

#include <iostream>
using namespace std;void TestRef()
{//像下面这种赋值,就产生了临时变量int i = 1;double b = i;//i是int类型,b是double类型,i会生成临时变量,临时变量复制给了bdouble d = 12.5;//int& ra = d;编译会报错,因为引用变量的类型是int&,而d的类型是double,类型不一致//有人可能会有疑问,他们不会发生隐式转换吗?不会,隐式类型转换的前提是一组相近类型之间的转换//例如:int double float等等他们都是描述数据的相似类型,之间可发生隐式类型转换。而上述的引用类型与double不一致const int& rb = d;//像这个,double类型的d会先发生隐式类型转换成int,然后由int类型的d生成临时变量,临时变量具有常属性//可以赋值给具有常属性的引用变量}int main()
{TestRef();return 0;
}

 四、使用场景

1.做参数

#include <iostream>
using namespace std;//在C++中,传参时可以用引用传参,就是给实参取个别名罢了,不会像C语言中的形参一样额外开空间
//好处就是减少了空间的开销
void Swap(int &left, int& right)
{int temp = left;left = right;right = temp;
}int main()
{int a = 3, b = 4;Swap(a, b);//注意:这里如果传的是常量,那么引用时需加上const,理由在临时变量那说的很清楚了return 0;
}

2.做返回值 

先说结论:如果函数返回时,除了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

来看分析这个代码: 

#include <iostream>
using namespace std;int& count()//引用函数可以看做是给这个count函数的别名
{static int n = 0;//定义了一个静态变量,该对象存放在静态区,不会随着count函数的销毁而销毁//生命周期是整个main函数的生命周期,只有main函数销毁了才回销毁n++;return n;//这里有个细节:对于传值返回的函数在进行返回值时,并不会直接返回这个值,中间其实会产生一个临时变量//在函数销毁时,这个变量也就是销毁了,返回的实际值其实是这个临时变量的值,对于临时变量存放位置取决于该对象的大小// 如果比较小的话 4/8bit——>寄存器//如果比较大的话 —— > 临时变量放在上一个栈帧(调用他的栈帧中)// //而对于传引用返回,并不会产生临时变量,返回的是这个值的别名////这里使用了引用返回,且count函数销毁时,n对象并没有销毁,赋值给了引用函数count
}int main()
{int& ret = count();//引用函数作为返回值给ret,其实就是相当于返回了n的别名count();cout << ret << endl;return 0;
}

运行结果:

再来对比一下这个代码:

#include <iostream>
using namespace std;int& Add(int a, int b)
{int c = a + b;//作用域只限定在这个函数内部,函数销毁时,该变量也会销毁return c;//此时传引用返回,而c又随着函数的销毁而销毁了,那么此时引用函数的值就是随机值了//所以对于返回对象出了函数作用域,要还给系统的,必须使用传值返回
}int main()
{int& ret = Add(1, 2);cout << "Add(1,2) is :" << ret << endl;return 0;
}

运行结果:

6.5 传值、传引用效率比较

对于以值作为传参的参数或者传值返回,并不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,对于传引用返回而言,是直接传回对象的别名,不需要进行拷贝。所以传值返回效率是非常低下的,尤其是对象很大时,还需要拷贝一份,效率更低。

例如:

#include <iostream>
using namespace std;#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a){}void TestFunc2(A& a) {}void TestValuetime()
{A a;//以值作为参数size_t begin1 = clock();//获取当前时间for (size_t i = 0; i < 10000; i++){TestFunc1(a);}size_t end1 = clock();//循环结束后,再获取当前时间//以引用作为参数size_t begin2 = clock();for (size_t i = 0; i < 10000; i++){TestFunc2(a);}size_t end2 = clock();cout << "TestFunc1-time:" << end1 - begin1 << endl;cout << "TestFunc2-time:" << end2 - begin2 << endl;
}int main() {TestValuetime();return 0;
}

运行结果:

通过代码比较,还是可以发现传值和引用在作为传参以及返回值类型上效率相差很大。

6.6引用和指针的区别

我们知道在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。 

其实在底层实现上实际是有空间的,引用是按照指针方式来实现的。我们写代码,相当于在上层的页面写代码,编译器进行编译时,是对上层的代码进行语法分析、语义分析、符号汇总等等,一定要区分语法概念和底层的区别,所以引用对于上层而言就是一个语法概念的存在

例子: 

#include <iostream>
using namespace std;int main() {int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

 该代码反汇编(先进入调试模式、右击代码,选中转反汇编):

 虽然他们在底层上实现是一样的,但在上层引用和指针在各方面还是有区别的:

1.引用概念上定义一个变量的别名,指针存储一个变量地址

2.引用在定义时必须初始化,指针没有要求

3.引用在初始化时引用一个实体后,就不能引用其他实体,而指针可以在任何时候指向任何一个同类型实体

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

5.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台占4个字节,64位平台占8个字节)

6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

7.有多级指针,但是没有多级引用(不管被引用多少次,始终是一个变量的别名)

8.访问实体方式不同,指针需要显示解引用,引用编译器自己处理

9.引用比指针使用起来相对更安全(引用定义时就与变量绑定,也不用操作地址,而指针定义时未初始化就是野指针,还可以通过修改地址来访问变量)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/155850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud 简介

1、简介 Spring CloudLevel up your Java code and explore what Spring can do for you.https://spring.io/projects/spring-cloud Spring Cloud 是一系列有序框架的集合&#xff0c;其主要的设施有&#xff0c;服务发现与注册&#xff0c;配置中心&#xff0c;消息总…

计算机组成原理-主存储器与CPU的连接

文章目录 知识总览单块存储芯片与CPU的连接位扩展&#xff08;存储字的位数&#xff09;字扩展&#xff08;存储字数&#xff09;关于线选法和片选法字位同时扩展总结补充&#xff1a;译码器 知识总览 单块存储芯片与CPU的连接 数据总线&#xff0c;地址总线&#xff0c;片选线…

Postman插件如何安装(一)

我们chrome插件网热门推荐的软件之一就是postman。但是postman的适应平台分为&#xff1a;postman chrome应用程序&#xff0c;postman应用程序&#xff0c;postman插件。谷歌应用商店从2018年3月开始停止chrome应用程序的更新。除非继续使用老版本的postman chrome应用程序&am…

【代码随想录】刷题笔记Day33

前言 Day33虽说是一个月&#xff0c;但是从第一篇开始实际上已经过了8个月了&#xff0c;得抓紧啊 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 前面组合就强调过差别了&#xff0c;这道题是排序&#xff0c;因此每次要从头到尾扫&#xff0c;结合used数组 class So…

数字IC基础:有符号数和无符号数的加减运算

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 首先说明&#xff0c;本篇文章并不涉及补码运算正确性的证明&#xff0c;仅是对补码运算在有符号数和无符号数中运行进行讨论。 补码运算最大的作用在于消除计算机…

机器学习8:在病马数据集上进行算法比较(ROC曲线与AUC)

ROC曲线与AUC。使用不同的迭代次数&#xff08;基模型数量&#xff09;进行 Adaboost 模型训练&#xff0c;并记录每个模型的真阳性率和假阳性率&#xff0c;并绘制每个模型对应的 ROC 曲线&#xff0c;比较模型性能&#xff0c;输出 AUC 值最高的模型的迭代次数和 ROC 曲线。 …

5 个适用于 Linux 的开源日志监控和管理工具

当Linux等操作系统运行时&#xff0c;会发生许多事件和在后台运行的进程&#xff0c;以实现系统资源的高效可靠的使用。这些事件可能发生在系统软件中&#xff0c;例如 init 或 systemd 进程或用户应用程序&#xff0c;例如 Apache、MySQL、FTP 等。 为了了解系统和不同应用程序…

UE5和UE4版本更新重大改变汇总。

转载&#xff1a;UE5和UE4版本更新重大改变汇总。 - 知乎 (zhihu.com) 用户界面变化&#xff1a; 1&#xff0c;原先拖动给放置Actor的place actors&#xff0c;世界大纲&#xff0c;Level等都可以通过右击隐藏到侧边栏&#xff1b; 2&#xff0c;Command命令窗口和ContentBr…

优秀智慧园区案例 - 佛山美的工业城零碳智慧园区,先进智慧园区建设方案经验

一、项目背景 美的工业园区西区最早建于上世纪90年代&#xff0c;到现在已经过去近30年&#xff0c;而这三十年恰恰是信息科技大发展的30年&#xff0c;原有的生产办公条件已不能很好的承载新时期办公和参观接待的需求。所以在21年美的楼宇科技事业部决定对原来的园区进行改造…

文本转语音

免费工具 音视频转译 通义听悟 | https://tingwu.aliyun.com/u/wg57n33kml5nkr3p 音色迁移 speechify | https://speechify.com/voice-cloning/ 视频生成 lalamu | http://lalamu.studio/demo/ 画质增强 topazlabs video AI | https://www.topazlabs.com 付费工具 rask | htt…

LeetCode热题100——动态规划

动态规划 1. 爬楼梯2. 杨辉三角3. 打家劫舍 1. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; // 题解&#xff1a;每次都有两种选择&#xff0c;1或者2 int climbStairs(int n) {if (n …

STM32CubeMX学习笔记-CAN接口使用

STM32CubeMX学习笔记-CAN接口使用 CAN总线传输协议1.CAN 总线传输特点2.位时序和波特率3.帧的种类4.标准格式数据帧和遥控帧从STM32F407参考手册中可以看出主要特性如下CAN模块基本控制函数CAN模块消息发送CAN模块消息接收标识符筛选发送中断的事件源和回调函数 CubeMX项目设置…

matlab设置背景颜色

matlab默认的背景颜色是纯白RGB(255,255,255)&#xff0c;纯白太刺眼&#xff0c;看久了&#xff0c;眼睛会酸胀、疼痛&#xff0c;将其改成豆沙绿RGB(205,123,90)&#xff0c;或者给出浅绿色RGB(128,255,255), 颜色就会柔和很多&#xff0c;眼睛感觉更舒适。     下面介绍在…

java springboot 在测试类中声明临时Bean对象

上文 java springboot在当前测试类中添加临时属性 不影响application和其他范围 中 我们讲了怎么在测试类中设置临时属性 但是 如果我们想设置临时的Bean呢&#xff1f; 其实做过几个项目的人都会理解 我们很多功能 需要一些第三方bean才能完成 那么 我们可能存在需要用第三方b…

Java实现windows系统截图

Java提供了一种方便的方式来截取Windows系统的截图。这个过程通常需要使用Java的Robot类来模拟用户的鼠标和键盘输入操作。下面将介绍如何使用Java实现Windows系统截图。 步骤1&#xff1a;导入Robot和AWT包 Java提供了一个Robot类&#xff0c;它可以模拟用户的键盘和鼠标操作…

2015-2020年全国地区生产总值及一二三产构成数据总览,shp/excel格式

今天我们来整理了2015-2020全国地区生产总值及一二三产构成数据&#xff0c;数据格式为shpexcel格式&#xff0c;数据精度可达各区县。 另外&#xff0c;需要说明的是&#xff1a;由于统计年鉴指标调整&#xff0c;每一年的数据并非字段相同&#xff0c;字段详情请参考已下载数…

梯度引导的分子生成扩散模型- GaUDI 评测

GaUDI模型来自于以色列理工Tomer Weiss的2023年发表在预印本ChemRxiv上的工作 《Guided Diffusion for Inverse Molecular Design》。原文链接&#xff1a;Guided Diffusion for Inverse Molecular Design | Materials Chemistry | ChemRxiv | Cambridge Open Engage GaUDI模型…

详解Python Tornado框架写一个Web应用全过程

Tornado是什么 之前在看Jupyter组件的源码的时候&#xff0c;发现了tornado这个web框架。 不仅仅做一个web框架&#xff0c; 通过使用非阻塞网络I/O&#xff0c;Tornado可以扩展到数万个开放连接。 这样非常适合 long polling &#xff0c; WebSockets 以及其他需要与每个用户…

shell脚本判断语句

目录 一. 判断语句 1. 判断文件是否存在 test 2. 数值比较 3. 字符串比较 4. 逻辑运算 5. [ ] 与 [ [ ] ] 6. ( ) 与 { } 7. if 语句 二. 脚本应用 一. 判断语句 1. 判断文件是否存在 test 选项 -a 和 -e 都可以判断文件是否存在 只是 -a 选项在取反时有问题&#xf…