一篇文章带你搞懂C++引用(建议收藏)

引用

6.1 引用概念

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

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

typedef 是给类型取别名

引用是给变量取别名

注意:引用类型必须和引用实体是同种类型的

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

int main()
{int a = 0;//定义一个变量a,赋值为0,int &b = a;//这里的&不是取地址符,而是引用,给变量取别名, &定义在一个类型和变量之间为引用//定义一个空间为a,又给这个空间a取别名为bint a = 0;int b = a;//这种写法和上面是完全不同的,//这里是 定义一个变量为a,a的值是0,定义一个变量为b,用a的0初始化return 0;
}

如何证明是否公用一块空间?


#include <iostream>
using namespace std;int main()
{int a = 0;int& b = a;cout << &b << endl;//取地址cout << &a << endl;//取地址a++;b++;return 0;
}

6.2 引用的特性

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

int main()
{int a = 1;int& b;//引用在定义时必须初始化return 0;
}

2. 一个变量可以有多个引用(可以取无限个别名)

int main()
{int a = 1;int &b = a;int &c = a;int &d = c;//还可以给别名取别名a++;return 0;
}

3. 引用一旦引用一个实体,再不能引用其他实体

指针指向一个实体后,可以改变,引用不可以改变

int main()
{int a = 1;int& b = a;int& c = a;int& d = c;int x = 10;//引用一旦拥有一个实体,再不能引用其他实体b = x;b是x的别名呢?还是x赋值为b?return 0;
}

这里把x赋值给b

6.3 常引用

权限不能放大

int main()
{int a = 13;int& b = a;//权限不能放大const int c = 20;//int& d = c;const int& d = c;//权限可以缩小,从只读的角度int e = 25;const int& f = e;      return 0;
}

隐式类型转换和强制类型转换都是会产生临时变量

所有的转换都不是对原变量进行转换和提升,而是之间产生临时变量

并不会改变原变量类型,

这里本质上是权限的放大和缩小

类型转换中间是会产生临时变量的,临时变量具有常性,相当于const修饰

int main()
{int ii = 1;doubble dd = ii;//int类型可以给double,会发生隐式类型转换double& rdd = ii;//double类型的数据可以变成int的引用吗?//不可以  这里不能引用的原因不是说类型不匹配,而是不能进行权限的放大const double& rdd = ii;//这里可以引用是因为权限的平移 中间产生的临时变量也是相当于const修饰的变量//此时rdd引用的不是ii,而是int转换成double之间产生的临时变量,//这个临时变量具有常性return 0;
}

const 可以把一个常量起一个别名

const int& x = 10;

应用场景:

如果使用引用传参,函数内如果不改变n,那么尽量用const引用传参

const引用传参会有非常强的接受度

        

6.4 引用的使用场景

1.做参数

a.输出型参数

b.大对象传参,提高效率

2.做返回值

a.输出型返回对象,调用者可以修改返回对象.

b.减少拷贝提高效率,

不是什么时候都可以使用传引用返回,要注意使用场景

出了作用域,返回对象还在可以用传引用返回

出了作用域,返回对象销毁.那么一定不能用引用返回,一定要用传值返回

1. 做参数 --(引用的输出型参数)

如果不用引用,传入的是实参的一份临时拷贝,形参的改变不会影响实参

如果想改变 必须使用指针 传入地址

在C++里,这里x是a的别名,y是b的别名,x和y的交换就是a和b的交换

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 3;int b = 5;cout <<"交换前:" << a << ' ' << b << endl;Swap(a, b);cout <<"交换后:" << a << ' ' << b << endl;return 0;
}

例如:有些书里会把数据结构里链表部分弄得很复杂

typedef struct SListNode
{.....
}SLTNode,*PSLTNode;
//这里的*PSLTNode 相当于typedef struct SListNode* PSLTNode  给这个结构体指针起了个别名 PSLTNode
void SListPushBack(PSLTNode& phead,int x)//这里的引用相当于 phead是list的别名,phead的改变会影响list
{.....
}
int main()
{SLTNode* list = NULL;SListPushBack(list,1);SListPushBack(list,1);SListPushBack(list,1);return 0;
}

大对象传参 提高效率

#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{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(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl; 
}

2. 做返回值

传值返回 都会生成一个返回对象拷贝作为函数调用的返回值

返回的是n吗 是用n的拷贝来做表达式的返回值

为什么编译器要这么做?

如果这里没有static ,n返回时,出了该作用域 会销毁 置为随机值

传引用返回:

引用返回的语法含义:返回返回对象的别名

不是什么时候都可以使用传引用返回,要注意使用场景

返回n的别名 越界了为什么不报错呢?

ret的结果是未定义的 如果栈帧结束时,系统清理栈帧置成随机值,那么这里ret的结果就是随机值

下面程序使用引用返回本质是不对的,结果是没有保障的

int& Count()
{int n = 0;n++;// ...return n;
}
int main()
{int ret = Count();return 0;
}

如果引用ret ,那么相当于 ret也是n的别名,结果会不会有所不同

int& Count()
{int n = 0;n++;// ...return n;
}
int main()
{int& ret = Count();printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);return 0;
}

总结:出了函数作用域,返回对象就销毁了,那么一定不能用引用返回,一定要用传值返回

什么时候可以用引用返回?

使用static

1. static修饰变量

   a. 函数中局部变量:

      声明周期延长:该变量不随函数结束而结束

      初始化:只在第一次调用该函数时进行初始化

      记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值

      存储位置:不会存储在栈上,放在数据段

int& Count()
{static int n = 0;n++;// ...return n;
}
int main()
{int& ret = Count();printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);printf("%d\n", ret);return 0;
}
const引用

为什么这里给c取别名不可以?

本质上是权相的放大 c自己是const类型 不可以修改

用d取别名 使得d是权限的放大 可以修改

#include <iostream>using namespace std;int main()
{int a = 10;//权限的的平移int& b = a;const int c = 20;//权限的放大int& d = c;int e = 30;//权限的缩小const int&f = e;//只读的角度变成你的别名return 0;
}

权限不可以放大,但是权限可以缩小

int main()
{int ii = 1;double dd = ii;//发生隐式类型转换double& rdd = ii;//double不可以变成int的引用//不可以使用的本质原因是 因为权限的放大,因为 int 类型要转换成double类型//中间要先生成一个double类型的临时变量,相当于 const double ii;//double& dd = const double ii; //权限的放大不可以const double& rdd = ii;//可以使用权限的平移return 0;
}

强制转换并不是改变原变量类型 他也是产生一个临时变量

如果使用引用传参,函数内如果不改变n,那么尽量用const引用传参

void func1(int& n)
{}
void func2(const int& n)
{}
int main()
{int a = 10;const int b =20;func1(a);func1(b);func1(30);func2(a);func2(b);func2(30);double c = 1.11;func2(c);return 0;
}

指针和引用的差别

指针和引用用途基本是相似的

但有

1.使用场景的差别

引用和指针的不同点:

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

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

实体

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

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

4个字节)

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

6. 有多级指针,但是没有多级引用

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

8. 引用比指针使用起来相对更安全

2.语法特性以及底层原理的差别

从语法角度而言,引用没有开辟空间,指针开了四个字节或者8个字节的空间

底层实现角度,那么引用底层是用指针实现的

个人水平不足 如果代码中有错误,可以多多在评论区指出,一定会及时修改!
谢谢大家看到这里 觉得有收获的话可以三连一下 一起加油!

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

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

相关文章

Linux.软件操作

1.yum 命令 要连网 2.systemctl 命令控制软件的启动和关闭 3.ln 创建软连接 使用cat来找本体&#xff0c;看看链接生不生效 4.date 命令查看系统时间 格式化的时候可以用双引号把他们引出来 -d 对时间进行修改 修改时区 自动校准 手动校准 5.ifconfig 查看本机的ip地址 6.h…

5.31.15 使用图像到图像转换和 YOLO 技术对先前的乳房 X 光检查结果中的异常进行早期检测和分类

在本研究中&#xff0c;我们研究了基于 You-Only-Look-Once (YOLO) 架构的端到端融合模型的有效性&#xff0c;该模型可同时检测和分类数字乳房 X 光检查中的可疑乳腺病变。包括四类病例&#xff1a;肿块、钙化、结构扭曲和正常&#xff0c;这些病例来自包含 413 个病例的私人数…

ic基础|复位篇02:芯片中的“人生重来枪”!crg之复位系统

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

范闲获取到庆帝与神庙的往来信件,用AES进行破解

关注微信公众号 数据分析螺丝钉 免费领取价值万元的python/java/商业分析/数据结构与算法学习资料 在《庆余年2》中&#xff0c;范闲与庆帝和神庙之间的权谋斗争愈演愈烈。一次偶然的机会&#xff0c;范闲从庆帝的密室中获取到几封与神庙往来的密信。然而&#xff0c;这封信件…

eclipse连接后端mysql数据库并且查询

教学视频&#xff1a;https://www.bilibili.com/video/BV1mK4y157kE/?spm_id_from333.337.search-card.all.click&vd_source26e80390f500a7ceea611e29c7bcea38本人eclipse和up主不同的地方如下&#xff0c;右键项目名称->build path->configure build path->Libr…

【悬架笔记三】1/4被动悬架垂向动力学仿真+频域特性分析

1/4被动悬架 代码&#xff1a; %书第156页、159页 clc clear close all %% 一.悬架参数 ms320; mw50; Ks22000; Cs1500; Kw195000; f00.07; %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 二.垂向振动动力学仿真 %% 二.1.状态方程 A [0 1 0 -1;.…

JavaSE 实战五子棋中国象棋(单机简易版)

介绍 JavaSE实践五子棋和中国象棋游戏&#xff0c;棋盘&#xff0c;棋子绘制&#xff0c;输赢判定重置棋盘&#xff0c;单机博弈。 五子棋棋盘 中国象棋棋盘 使用说明 启动类 Main.java&#xff0c; 面板类 Panel.java绘制棋盘和玩法&#xff0c;实体类 ChessPiecesNode.jav…

【Text2SQL 论文】MAC-SQL:多个 Agents 合作来解决 Text2SQL

论文&#xff1a;MAC-SQL: A Multi-Agent Collaborative Framework for Text-to-SQL ⭐⭐⭐⭐ arXiv:2312.11242, 北航 & Tencent Code: MAC-SQL | GitHub 文章目录 一、论文速读二、MAC-SQL2.1 Selector agent2.2 Decomposer agent2.3 Refiner agent 三、指令微调的 SQL-L…

【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义

目录 问题解决方案讨论 问题 本文讨论一些按照特定的文本模式进行的查找和匹配。 解决方案 如果想要匹配的只是简单文字&#xff0c;通常我们使用一些内置的基本字符串方法即可&#xff0c;如&#xff1a;str.find()&#xff0c;str.startwith()&#xff0c;str.endswith() …

Day49 动态规划part08

LC139单词拆分(未掌握) 未掌握分析&#xff1a;将字符串s中的各个字符看成是背包&#xff0c;思考成了多重背包问题单词就是物品&#xff0c;字符串s就是背包&#xff0c;单词能否组成字符串s&#xff0c;就是问物品能不能把背包装满。拆分时可以重复使用字典中的单词&#xf…

转速传感器介绍

一、概述 RPM&#xff08;Revolutions Per Minute&#xff09;转速传感器是一种用于测量旋转机械设备转速的传感器。它可以检测旋转部件上的特定位置标记&#xff08;如齿轮、凸起或磁铁&#xff09;&#xff0c;并根据这些标记的通过频率来计算转速。发电额定频率是50hz和60z…

java线程变量共享

在Java中&#xff0c;线程变量共享可以通过几种方式实现&#xff1a; 1.实例变量&#xff1a;如果一个实例变量被多个线程共享&#xff0c;你需要确保适当的同步&#xff0c;以避免竞态条件。你可以使用synchronized关键字或者Lock接口来保护共享变量。 2.静态变量&#xff1a;…

openh264 降噪功能源码分析

文件位置 ● openh264/codec/processing/denoise/denoise.cpp ● openh264/codec/processing/denoise/denoise_filter.cpp 代码流程 说明&#xff1a;从代码流程可以看到&#xff0c;实现降噪的核心功能主要就是BilateralDenoiseLuma、WaverageDenoiseChroma两个函数。 原理…

SOA主要协议和规范

Web服务作为实现SOA中服务的最主要手段。首先来了解Web Service相关的标准。它们大多以“WS-”作为名字的前缀&#xff0c;所以统称“WS-*”。Web服务最基本的协议包括UDDI、WSDL和SOAP&#xff0c;通过它们&#xff0c;可以提供直接而又简单的Web Service支持&#xff0c;如图…

代码随想录算法训练营第十五天| 110.平衡二叉树、 257. 二叉树的所有路径、404.左叶子之和

110.平衡二叉树 题目链接&#xff1a;110.平衡二叉树 文档讲讲&#xff1a;代码随想录 状态&#xff1a;还可以 思路&#xff1a;计算左右子树的深度差&#xff0c;递归判断左右子树是否符合平衡条件 题解&#xff1a; public boolean isBalanced(TreeNode root) {if (root n…

覆盖路径规划经典算法 The Boustrophedon Cellular Decomposition 详解

2000年一篇论文 Coverage of Known Spaces: The Boustrophedon Cellular Decomposition 横空出世&#xff0c;解决了很多计算机和机器人领域的覆盖路径问题&#xff0c;今天我来详细解读这个算法。 The Boustrophedon Cellular Decomposition 算法详解 这篇论文标题为"C…

数字模拟EDA研发环境搭建

中小企业数字模拟EDA研发环境部署、集群搭建、网络配置、硬件咨询、数据备份、技术指导、环境生命周期维护等&#xff0c;Cadence、Synopsys、Mentor、Keysight、ANSYS&#xff0c;MATLAB、Xilinx等厂商软件工具安装调试。 EDA研发环境搭建经验交流&#xff0c;请加V

【Neo4j】Windows11使用Neo4j导入CSV数据可视化知识图谱

Windows11使用Neo4j导入CSV数据可视化知识图谱 序1. 安装JDK21&#xff08;1&#xff09;下载&#xff08;2&#xff09;安装&#xff08;3&#xff09;环境配置 2. 安装Neo4j&#xff08;1&#xff09;下载&#xff08;2&#xff09;解压安装&#xff08;3&#xff09;环境配置…

初识C++ · 模板进阶

目录 前言&#xff1a; 1 非类型模板参数 2 按需实例化 3 模板特化 4 模板的分离编译 前言&#xff1a; 前面模板我们会了简单的使用&#xff0c;这里带来模板的进阶&#xff0c;当然&#xff0c;也就那么几个知识点&#xff0c;并不太难。 1 非类型模板参数 先来看这样…

嵌入式移植jpeglib--Linux交叉编译ARM平台

一 、交叉编译jpeg库 1.下载源码tar.gz 2. 源码目录下执行 jpeglib配置文件 ./configure CCarm-none-linux-gnueabihf-gcc LDarm-none-linux-gnueabihf-ld --prefix/work/jpeg_arm_lib --exec-prefix/work/jpeg_arm_lib --enable-shared --enable-static --hostarm-none-linu…