C++入门——引用(2)

news2025/4/21 11:05:22

前言

上一节我们开始学习了C++,并且对C++有了初步的了解,这一节我们继续学习C++的基础,那么废话不多说,我们正式进入今天的学习

C++中的引用

1.1引用的概念

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

引用的语法如下:

	int a = 0;
	int& b = a;

第二行的代码的意思是:给已创建的变量a取一个别名为b,注意这里的&符号不是取地址的意思,而是引用的意思

当&符号放在一个类型和一个变量的中间位置才叫做引用,不然的话仍然起的是取地址的功能。

int main(void)
{
	int a = 0;
	int& b = a;

	cout << &a << endl;
	cout << &b << endl;
	return 0;
}

通过运行以上代码我们可以知道:引用并没有重新开辟一个空间,而是和原变量共用一个空间

我们对b变量执行++操作也相当于对a变量执行++操作,因为它们本质上就是同一个变量

引用的概念有点像我们在日常生活中给别人起的外号

学到这里可能有人会觉得引用没有什么用,只是给变量取了一个“外号”罢了,其实并不是这样的。我们在C语言中若是要完成交换两个不同变量中的数据内容时,我们创建swap函数应该要传入两个变量的地址,如果是传值调用则无法完成交换的功能,因为在出函数的时候临时的变量被销毁。但是有了引用就可以不用使用指针,引用传参修改的值可以直接影响到原来的参数

void swap(int& x1, int& x2)
{
	int tmp = x1;
	x1 = x2;
	x2 = tmp;
}

int main(void)
{
	int x = 1;
	int y = 2;
	swap(x, y);
	cout << "x = " << x << endl;
	cout << "y = " << y << endl;
	return 0;
}

1.2引用的注意事项

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

 int a = 10;
 // int& ra;   // 该条语句编译时会出错

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

int a = 0;
int& ra = a;
int& rra = a;

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

int a = 0;
int& b = a;
int x = 1;
b = x;
//这种情况下并不是把b变成x的引用,而是给b中赋值为1,也就是a改为1

4.引用的类型必须和引用实体的类型相同

1.3传引用返回

首先我们需要了解一个概念,叫做传值返回:

int Count()
{
	int n = 0;
	n++;
	//……
	return n;
}

int main(void)
{
	int ret = Count();
	return 0;
}

在出函数的时候变量n已经被销毁了,所以函数并不是直接拿n作为返回值,此时编译器用以下两种方式返回

1.把n拷贝到一个寄存器中,让寄存器充当返回值,该情况适用于返回值比较小的情况

2.当n的取值比较大的的时候,会在Count函数和main函数之间的空隙里面压出一个空间,将值存入并将它作为一个返回值

随后我们来了解一下引用返回

int& Count()
{
	int n = 0;
	n++;
	//……
	return n;
}

int main(void)
{
	int ret = Count();
	return 0;
}

传引用返回相当于返回的是值n的别名,这个概念看起来有些奇怪,因为原来的变量n已经被销毁了,而返回的值又是已经被销毁的变量的别名,所以有的人可能认为这个概念的性质和野指针差不多 。首先我们需要知道的是,当一个变量或者一个空间被销毁了,仍然可以返回这个已经被销毁的空间里面的变量的别名,因为空间被销毁并不是意味着这一块空间已经没有了。空间销毁的概念有点类似于我们在日常生活中的“退房”,我们销毁了的那块空间并不是不能使用了,而是收回了对那块空间的使用权。但是传引用返回是比较危险的,传引用返回一般都会报一个警告,返回来的值可能是正常值也有可能是一个随机值,这取决于函数栈帧销毁了以后原空间里面的内容会不会被重置为一个随机值

int& Count()
{
	int n = 0;
	n++;
	//……
	return n;
}

int main(void)
{
	int& ret = Count();
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}

我们来看一下这样的情况下为什么第二次打印的结果是一个随机值:

我们首先需要了解,cout是一个函数调用,调用的是一个运算符重载的函数,cout是ostream类型

我们在第一次调用函数的时候并不会出现任何的问题,而当我们第二次调用函数的时候,创建栈帧的区域还是在第一次调用所创建的区域,此时区域内原先的数据就已经被覆盖了,所以打印出来的是一个随机值

我们来举一个例子就能更好地理解这一点:

int& Add(int a, int b)
{
	int c = a + b;
	return c;
}

int main(void)
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1,2) is :" << ret << endl;
	return 0;
}

因为本来执行Add操作计算出来的值是3,但是我们在第二次调用函数的时候算出来的值是7,第二次调用覆盖了第一次调用,所以此时去打印算出来的值是7

所以:如果函数返回时,出了函数作用域,如果返回对象还在(还没有还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回

我们在C语言中要完成顺序表的第i个位置的数据和修改需要两个步骤:

struct Seqlist
{
	int* a;
	int size;
	int capacity;
};
//读取第i个位置的值
//修改第i个位置的值
int SLAT(struct Seqlist* ps, int i)
{
	assert(i < ps->size);
	//...
	return ps->a[i];
}

int SLModify(struct Seqlist* ps, int i, int x)
{
	assert(i < ps->size);
	//...
	return ps->a[i] = x;
}

而在C++中使用引用返回就可以简化这一过程:

struct Seqlist
{
	int* a;
	int size;
	int capacity;
};
//读取&修改第i个位置的值
int& SLAT(struct Seqlist& ps, int i)
{
	assert(i < ps.size);
	//...
	return ps.a[i];
}
int main(void)
{
	struct Seqlist s;
	//...
	SLAT(s, i) = 1;
	cout << SLAT(s, i) << endl;
	return 0;
}

当出了作用域时,ps.a[i] 仍然存在,所以可以直接对其修改,修改过后的值仍然存在

怎么解释这个现象呢?

因为传值返回出函数的时候返回的是一份临时的拷贝,是不可以直接修改的

而传引用返回返回的是别名,是可以被修改的

传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。如果是传引用的话就能够提高效率,当然,传指针也可以

#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;
}

int main(void)
{
	TestRefAndValue();
	return 0;
}

由此我们可以看出:传引用返回比传值返回的效率要高

那么在什么情况下适合使用传引用返回呢?

1.返回的是一个全局对象

2.返回的是一个静态对象

3.在堆上动态申请的对象

因为这三个变量出了作用域仍然存在,使用传引用返回就可以在确保没有错误的情况下提高效率

此时我们就可以总结一下:

传引用传参的优势(在任何的情况下都可以

1.提高效率

2.输出型参数(形参的修改可以影响实参)

传引用返回的优势(出了函数作用域对象还在才可以使用

1.提高效率

2.修改返回的对象

1.4常引用

int main(void)
{
	const int a = 0;
	int& b = a;
	return 0;
}

在这种情况下,编译是无法通过的,因为这是一种权限的放大。在引用的过程中权限是可以平移和缩小的,但是不能被放大

权限的平移:

const int a = 0;
//权限的平移
const int& c = a;

权限的缩小:

int x = 0;
//权限的缩小
const int& y = x;

注意:赋值是不受权限的影响的,因为赋值是一种拷贝,b的修改不影响a

const int a = 0;
//赋值
int b = a;

我们再来看一个有趣的现象:

我们这样写出的代码编译会失败:

int i = 0;
double& d = i;

而这样写编译就不会报错:

int i = 0;
const double& d = i;

第一种情况其实是一种权限的放大,临时变量具有常性

而第二种情况我们加入了const,此时就没有权限的放大了

1.5引用与指针的区别

我们通过之前的学习可以知道:指针在创建的时候会在内存中开辟空间,而在语法上来看引用是不会额外的开辟空间的(其实在底层实现上引用也会占用空间,但是在语法的层面上不会占用空间)

引用和指针的不同点:

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

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

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

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

5.sizeof的含义不同:引用结果是引用类型的大小,但是指针始终是地址空间所占用的字节数(4或者8)

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

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

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

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

结尾

引用是C++中的一个重要的概念,我们需要加深对引用的理解,有助于我们更好的学习C++,那么本节的内容到此就结束了,谢谢您的浏览!!!

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

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

相关文章

限流算法(令牌桶漏桶计数器)

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Spring⛺️稳中求进&#xff0c;晒太阳 业务重的三种情况&#xff1a;突发流量、恶意流量、业务本身需要 限流: 是为了保护自身系统和下游系统不被高并发流量冲垮&#xff0c;导致系统雪崩…

jQuery-2.鼠标焦点事件、节点操作、遍历元素、效果

鼠标事件 鼠标事件是当用户在文档上移动或单击鼠标时而产生的事件&#xff0c;常用的鼠标事件&#xff1a; 方法 描述 执行时机 click() 触发或将函数绑定到指定元素的click事件 单击鼠标时 mouseover() 触发或将函数绑定到指定元素的mouse over事件 鼠标移过时 mous…

体重秤蓝牙语音芯片方案-WT2605蓝牙音频ic在电子秤上的应用

在快节奏的现代生活中&#xff0c;健康成为了每个人关注的焦点。而体重作为健康指标之一&#xff0c;更是备受关注。如今&#xff0c;一款全新的智能体重秤蓝牙语音芯片方案正悄然改变着我们的健康管理方式&#xff0c;让健康触手可及。 性能&#xff1a; 1&#xff1a;蓝牙语…

.Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 发布到 Win7+

.Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 实测可以完整运行在 win7sp1/win10/win11. 如果用其他工具打包,还可以运行在mac/linux下, 传送门BlazorHybrid 发布为无依赖包方式 安装 WebView2Runtime 1.57 MB或136 MB 测试DEMO 发布为依赖包方式 安装 WebView2Runtime 1.…

渗透测试工具及插件第二期

一、OWASP Penetration Testing Kit 这个工具他集成了中间件&#xff0c;等版本信息&#xff0c;漏洞信息&#xff0c;url&#xff0c;标识头等信息&#xff0c;WAF/CDN识别&#xff0c;密匙等信息&#xff0c;多种信息的功能上集合的插件。 说明书&#xff1a;https://micros…

pwn(一)前置技能

以下是pwn中的题目&#xff08;漏洞&#xff09;类型&#xff1a; 关于pwn的学习&#xff1a; 一.什么是pwn&#xff1f;&#xff08;二进制的漏洞&#xff09; "Pwn"是一个俚语&#xff0c;起源于电子游戏社区&#xff0c;经常在英语中用作网络或电子游戏文化中的…

qt 5.15.x 安装android过程记录

1.经过好几天的qt for android 安装&#xff0c;发现存在很多坑 参考其他文章可以编译出APK文件。但是我发现(我的机器上)无法调试apk程序&#xff0c;不能调试那怎么行呢&#xff0c;看了很多文章都是运行出结果了就结束了。没有展示怎么调试程序。 很多文章都是建议安装JDK8…

Docker安装教程使用

一、Docker简介 什么是docker&#xff1a; docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上, 也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口什…

低代码在物品领用领域数字化转型的案例分析

办公用品管理数字化不仅代表了企业管理模式的革新&#xff0c;更是提升运营效率和成本控制的关键举措。通过数字化手段&#xff0c;企业能够实现采购、库存、领用等流程的自动化和智能化管理&#xff0c;大幅减少人工操作&#xff0c;提高处理速度&#xff0c;确保数据的准确性…

如何申请通配符SSL证书——值得收藏

申请通配符SSL证书的过程大致可以分为以下几个步骤&#xff1a; 1. 选择CA机构&#xff1a; 首先&#xff0c;您需要选择一个受信任的证书颁发机构&#xff08;Certificate Authority&#xff0c;简称CA&#xff09;&#xff0c;如DigiCert、GlobalSign、或JoySSL。确保所选机构…

2023年数维杯国际大学生数学建模挑战赛B题棉花秸秆热解的催化反应解题全过程论文及程序

2023年数维杯国际大学生数学建模挑战赛 B题 棉花秸秆热解的催化反应 原题再现&#xff1a; 随着全球对可再生能源需求的不断增加&#xff0c;生物质能作为一种成熟的可再生能源得到了广泛的关注。棉秆作为一种农业废弃物&#xff0c;由于其富含纤维素、木质素等生物质成分&am…

LangChain:模型 I/O 封装使用解析和感触

目录 模型 API&#xff1a;LLM vs. ChatModel OpenAI 模型封装 多轮对话 Session 封装 换个国产模型 模型的输入与输出 Prompt 模板封装 PromptTemplate ChatPromptTemplate MessagesPlaceholder 从文件加载 Prompt 模板 TXT模板 Yaml模板 Json模板 输出封装 Out…

[代码比较工具下载及使用]你真的需要一个代码比较工具

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到资源分享系列 这里有你想要的各种高质量资源 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读 如何低成本搭建个人网站 …

被称为“数智化黑马”的红海云,凭何连续四年登上HR服务品牌百强榜?

近日&#xff0c;中国领先的人力资源媒体机构HRoot发布了2023年中华区人力资源服务机构品牌100强榜单。该榜单经历经十余年&#xff0c;评选标准从最初的品牌影响力&#xff0c;扩大至人力资源服务机构的财务状况、成长性、创新性等更多维度。该榜单分为人力资源服务、人力资源…

十进制整数转平衡三进制

求解原视频&#xff1a;平衡三进制 求赞&#xff01;100赞买个乒乓球拍&#xff01;_哔哩哔哩_bilibili 题目&#xff1a; 上海市计算机学会竞赛平台 | YACS 求解程序&#xff1a; using namespace std; #include <iostream> #include <cstring>string work(int n…

李廉洋:5.13黄金原油消息面面和行情分析,必看策略。

黄金方面&#xff1a;月初公布的美国非农等就业市场数据比较弱势&#xff0c;显示美国就业市场开始走软&#xff0c;美联储在就业市场开始变差的背景下&#xff0c;存在提前降息的可能性&#xff0c;这有利于推动金价走高。The         近期公布的美国5月密歇根大学消费者…

2024终南山整形美容学院首届全国腹壁整形学术交流会 国际医学顺利开展

四月芳菲尽&#xff0c;五月絮升华。5月11日&#xff0d;12日&#xff0c;《2024终南山整形美容学院首届全国腹壁整形学术交流会暨第二届崔鑫腹壁整形学习班》在西安国际医学中心医院如期召开。来自全国各大整形外科同行精英们&#xff0c;济济一堂&#xff0c;共同交流探讨腹壁…

五月采购节 | 全场板卡八七折起

淘宝搜索【北京迅为电子官方企业】 5月13日~5月15日 海量优惠券等你拿&#xff01; 复制下方链接到淘宝 直接进入店铺&#xff01; https://shop459378556.taobao.com

项目-坦克大战-让坦克动起来

为什么写这个项目 好玩涉及到java各个方面的技术 1&#xff0c;java面向对象 2&#xff0c;多线程 3&#xff0c;文件i/o操作 4&#xff0c;数据库巩固知识 java绘图坐标体系 坐标体系-介绍 坐标体系-像素 计算机在屏幕上显示的内容都是由屏幕上的每一个像素组成的像素是一…

netty配置SSL、netty配置https(生产环境)

netty配置SSL、netty配置https&#xff08;生产环境&#xff09; 上一篇提到了如何在开发环境使用SSL&#xff1a;https://lingkang.top/archives/netty-pei-zhi-ssl 转自&#xff1a;https://lingkang.top/archives/netty-pei-zhi-https 那么netty如何使用可信任的证书呢&a…