初始C++(三):引用
文章目录
- 一.引用的概念
- 二.引用的使用
- 1.引用作为输出型参数
- 2. 引用作为函数返回值
- 3.const引用
- 三.引用的一些小问题
- 四.引用和指针
- 五.引用和指针的区别
一.引用的概念
引用的作用是给一个已经存在的变量取别名,编译器不会为引用变量开空间,引用变量和被他引用的变量共用一块空间。
二.引用的使用
//类型& 引用变量名(对象名) = 引用实体;
int i = 10;
int& j = i;//j就是i的引用,也可以说j就是i的别名
上面的i和j公用一块空间:
完全可以认为i,j代表的是一个东西。比如对i++使i变成11的时候,j也会变成11:
1.引用作为输出型参数
在我们学C语言的时候,应该遇到过交换函数,就是要求写一个函数来交换两个变量的值,当时是这样写的:
void Swap(int* i, int* j)
{int tmp = *i;*i = *j;*j = tmp;
}
因为函数的形参是实参的一份临时拷贝,也就是说形参的改变不会影响到实参的变化,所以这里我们要传递需要改变的两个变量的地址,这样在Swap函数里解引用才能找到需要改变的两个变量的值。
但是每次使用都要传地址,这样显得就非常麻烦,于是C++里的引用在这里就派上了大用场,现在这个交换函数可以这样写:
void Swap1(int& i, int& j)
{int tmp = i;i = j;j = tmp;
}
int main()
{Swap1(10,20);return 0;
}
这里的形参i,j不是实参的临时拷贝了,而是两个实参的别名,对两个别名的交换就可以认为是对实参两个变量的交换。
2. 引用作为函数返回值
首先看这样的一段代码:
int f()
{int n = 0;n++;return n;
}int main()
{int ret = f();return 0;
}
来了解一下n这个值是怎么传给ret的:
1.在f()这个函数运行完之前变量n的值首先会拷贝到一个临时变量中。
2.然后f()函数结束,这个函数的空间被销毁
3.最后临时变量的值赋值给变量ret.
小知识点:临时变量
如果需要拷贝的值很小,临时变量可以是用寄存器来代替,如果很大,比如像一个结构体,那这个临时变量是在f()的上层函数中直接帮你开辟好的,这个上层函数可以认为是调用f()函数的函数,临时变量具有常性,可以理解为被const修饰了一样。
在函数值返回,隐式/显式类型转换的时候都会产生临时变量
int a = 10;
cout << (double)a << endl;//这里是显式转换
double b = a;//这里是隐式转换
接下来在看一段代码:
int f1()
{static int n = 0;n++;return n;
}int main()
{int ret = f1();return 0;
}
虽然这里的n变成了静态的变量,储存在静态区,f()函数销毁后n不会被销毁,但是计算机仍然会将n拷贝到一个临时变量中,然后再由这个临时变量返回给ret.
这里的变量n完全可以不用进行拷贝,所以上面的代码可以进行一些优化:
int& f1()//将值返回变成引用返回
{static int n = 0;n++;return n;
}int main()
{int ret = f1();return 0;
}
如果将值返回变为引用返回,返回的值将不再是临时变量,而是n的引用,也可以说返回的就是n这个变量。这样就可以减少中间拷贝的过程。
所以在返回的变量在函数销毁的时仍然存在的情况下,返回值就可以用引用返回。
明白了这一点,还可以写这样的一种代码:
//定义一个数组结构体
typedef struct Array
{int a[10];
}Array;//定义一个函数用来寻找数组中第i个位置上的值
int& at(Array& ay, int i)
{assert(i < 10);return ay.a[i]; //形参用引用来接收,ay.a[i]中的ay是main函数中定义的那个数组的别名//返回值用引用,返回的就是main函数中定义的那个数组的别名
}int main()
{Array ay; //定义一个结构体for (int i = 0; i < 10; i++){//既然返回值就是自己定义的结构体里的数组,//所以对其赋值也是完全可以at(ay, i) = i;}for (int i = 0; i < 10; i++){cout << at(ay, i) << ' ';}cout << endl;return 0;
}
通过这段代码,引用返回不但可以减少拷贝,还可以对返回值进行修改。这里的at函数返回的就是数组里第i个元素,at(ay, i) = i就可以认为对第i个元素进行赋值。
3.const引用
先说结论:指针/引用在初始化和赋值的时候只能权限保持和权限缩小,不能权限放大。
权限放大:
int main()
{const int a = 10;int& b = a;return 0;
}
变量a的类型是const int说明它具有常属性,也就是不能被改变,但是a的别名b的类型是int反而可以改变了,这就是所谓的权限放大。如果这样写代码,编译器会报错的。
权限保持/权限缩小:
int main()
{//权限保持const int a = 10;const int& b = a;//权限缩小int x = 10;const int& y = x;return 0;
}
权限保持和缩小是没问题的。指针在这一块和引用是一样的,这里就不再复述了。
三.引用的一些小问题
- 引用类型必须和引用实体是同种类型的
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
四.引用和指针
在语法概念这个层次上引用是不开空间的,而指针是需要开空间的。接下来通过代码的汇编指令,看看引用和指针有没有区别:
int main()
{int a = 10;int* pa = &a;*pa = 20;int& ra = a;ra = 20;return 0;
}
虽然你可能不动这些指令是什么,但你只要看指针和引用有没有区别就行。
不难发现,引用和指针在底层的指令是一模一样的。所以说,虽然表面上引用和指针是两码事,但在底层,引用其实就是指针。
五.引用和指针的区别
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位平台下占8个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
相关文章:

初始C++(三):引用
文章目录一.引用的概念二.引用的使用1.引用作为输出型参数2. 引用作为函数返回值3.const引用三.引用的一些小问题四.引用和指针五.引用和指针的区别一.引用的概念 引用的作用是给一个已经存在的变量取别名,编译器不会为引用变量开空间,引用变量和被他引…...

【前端】参考C站动态发红包界面,高度还原布局和交互
最近有些小伙伴咨询博主说前端布局好难,其实都是熟能生巧! 模仿C站动态发红包界面,cssdiv实现布局,纯javascript实现交互效果 目录 1、界面效果 2、界面分析 2.1、整体结构 2.2、标题 2.3、表单 2.4、按钮 3、代码实现 3.…...

VR全景带你浪漫“狂飙”情人节,见证甜蜜心动
当情人节遇上VR,足以让情侣过一个难忘的情人节。马上情人节就要到了,大家是不是还在绞尽脑汁的想着,如何和另一半过一个浪漫的情人节呢?老套的剧情已经不能吸引人了,让我们看看VR全景给情人节带来了哪些不同的体验吧&a…...

Linux系统安全之iptables防火墙
目录 一.iptables防火墙基本介绍 二.iptables的四表五链 三.iptables的配置 1.iptables的安装 2.iptables防火墙的配置方法 四.添加、查看、删除规则 1.查看(fliter)表中的所有链 iptables -L 2.使用数字形式(fliter)表所有链 查看输出结果 iptables -nL 3.清空表中所…...
【C#基础】C# 变量与常量的使用
序号系列文章1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析3【C#基础】C# 数据类型总结文章目录前言一. 变量(variable)1,变量定义及初始化2,变量的类别3,接收输出变量二. 常量(constantÿ…...

[ 常用工具篇 ] CobaltStrike(CS神器)基础(一) -- 安装及设置监听器详解
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...

Redis集群
Redis集群 本章是基于CentOS7下的Redis集群教程,包括: 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖: yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录ÿ…...

00---C++入门
1. C关键字(C98) C总计63个关键字,C语言32个关键字 2. 命名空间 在C/C中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进…...

Spring-事务2
文章目录前言一、事务的特性(ACID)二、事务的隔离级别三、spring中的事务平台事务管理器.事务定义ISOLation_XXX:**事务隔离级别.**PROPAGATION_XXX:**事务的传播行为**.事务状态关系:四、使用XML文件配置事务1、 搭建…...

Windows Git Bash 配置
Windows Git Bash 配置 本文参考的文章: 在 Windows 的 Git Bash 中使用包管理器 - iris (ginshio.org)Git bash 安装 pacman & Windows 解压 zst 文件 | 伪斜杠青年 (lckiss.com) 一、Git的安装 Git 的安装应该是都会的,但还是应该说以下&#…...
java代码整合kettle9.3实现读取表中的数据,生成excel文件
java代码整合kettle9.3实现读取表中的数据,生成excel文件 1.简介 本次使用java代码整合kettle9.3版本,数据库使用mysql。 2.jar包导入 项目需要依赖部分kettle中的jar包,请将这部分jar包自行导入maven仓库。 <dependency><groupId…...

分享微信点餐小程序搭建步骤_微信点餐功能怎么做
线下餐饮实体店都开始摸索发展网上订餐服务。最多人选择的是入驻外卖平台,但抽成高,推广还要另买流量等问题,也让不少商家入不敷出。在这种情况下,建立自己的微信订餐小程序,做自己的私域流量是另一种捷径。那么&#…...

4、数组、切片、map、channel
目录一、数组二、切片三、map四、channel五、引用类型一、数组 数组: 数组是块连续的内存空间,在声明的时候必须指定长度,且长度不能改变所以数组在声明的时候就可以把内存空间分配好,并赋上默认值,即完成了初始化数组…...
270 uuid
270 uuid 用途 For the creation of RFC4122 UUIDs 可靠性 10000 星星 适应于浏览器或者服务器 官网链接 https://www.npmjs.com/package/uuid https://github.com/uuidjs/uuid 基本使用 import { v4 as uuidv4 } from uuid; uuidv4(); // ⇨ 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3d…...

2023最新简历模板免费下载
下面分享5个简历模板网站,免费下载,建议收藏! 2023用最漂亮的简历模板,让面试官眼前一亮。 1、菜鸟图库 个人简历模板|WORD文档模板免费下载 - 菜鸟图库 菜鸟图库除了有超多设计类素材之外,还有很多办公类素材&#…...

【CSS】元素居中总结-水平居中、垂直居中、水平垂直居中
【CSS】元素居中一、 水平居中1.行内元素水平居中(1)text-align2.块级元素水平居中2.1 margin(1)margin2.2布局(1)flex justify-content(推荐)(2) flexmargin…...
spring实现AOP
文章目录前言一、AOP的底层实现原理二、AOP的两种开发模式1.使用xml配置文件1.1 添加AOP依赖1.2 创建UserService1.3创建UserServiceImpl1.4创建通知类1.5 创建applicationContext.xml(添加aop约束)1.6 测试2.使用注解开发2.1 创建bean.xml文件配置注解方…...
neovim搭建cpp环境
文章目录Windowns下NeoVim搭建cpp环境NeoVim安装插件vim-plugindentLinevim-airlinectagstagbarcoc.vimWindowns下NeoVim搭建cpp环境 在开发过程中习惯在DIE环境中使用vim作为编辑器,在单独的编辑器也常使用gvim图形化编辑器。最近看到NeoVim的特性及兼容性方面不输…...
SpringBoot AES加密 PKCS7Padding 模式
AES 简介:DES 全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS) AES 密码学中的高级加密标准(Advan…...

按键输入驱动
目录 一、硬件原理 二、添加设备树 1、创建pinctrl 2、创建节点 3、检查 编译复制 三、修改工程模板编辑 四、驱动编写 1、添加keyio函数 2、添加调用 3、驱动出口函数添加释放 4、添加原子操作 5、添加两个宏定义 6、初始化原始变量 7、打开操作 8、读操作 总体代…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...