[C++: 引用】

news2025/4/8 9:30:53

To shine,not be illuminated.

目录

1 引用概念

2 引用特性

3 常引用

4 使用场景

 4.1 引用做参数

4.2 做返回值

5 传值、传引用效率比较

 6 引用和指针的区别

7 总结


1 引用概念

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

比如:你的正式姓名和你的小名或者别名。

使用方法:

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

我们可以来举个例子:

int main()
{
	int a = 10;
	int& sa = a;
	int b = 20;
	int& sb = b;
	return 0;
}

 通过调试我们也能够发现a和sa其实共用的是同一块空间,这也就解释了为啥引用只是给变量取了一个新名字,并没有为引用变量开辟新的空间。

注意:正确用法: 引用类型 必须和引用 实体 同种类型

2 引用特性

  • 1. 引用在定义时必须初始化
  • 2. 一个变量可以有多个引用
  • 3. 引用一旦引用一个实体,再不能引用其他实体

 我们一个一个来看:

假如引用变量不初始化

int main()
{
	int a = 10;
	int& sa ;
	
	return 0;
}

 这种方式显然是会直接报错的:

 一个引用变量可以有多个引用:

int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	
	return 0;
}

这里b和c都是a的别名,修改其中任何一个这3个的值都会发生改变。

假如拿一个已经引用过的实体再去引用其他实体:

 这样写直接就报错了,有人会想到换一种方式写呢:

int main()
{
	int a = 10;
	int& b = a;
	int e = 20;
	b = e;
	
	return 0;
}

这里b还是e的引用吗?

显然不是的,这里只是将e的值赋给了b,b还是a的引用,程序结束后a和b都应该为20,我们可以打开监视窗口看看:


3 常引用

我们来看下面这个栗子:

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

上述代码能够被编译通过吗?

 很明显这种写法是错误的,C++认为这种写法是不安全的,const int是只读权限,而int&却是既有读权限也有写权限,像这种权限放大C++是不支持的,权限缩小或者权限相等C++是支持的。

比如下面这两种写法都是合法的:

int main()
{
	//权限相等
	const int a = 10;
	const int& b = a;
	//权限缩小
	int c = 20;
	const int& d = c;
	return 0;
}

再来看下面一段代码:

int main() 
{
	double d = 12.12;
	int& i = d;
	return 0;
}

上面代码能够编译通过吗?

 我们可能会想:引用类型和引用实体必须是同一种类型的,所以说就错误了呗。

引用类型和引用实体一定要是同一种类型的吗?

我们将程序再修改一下:

 我们发现程序居然能够跑过,只是错误变成了一个警告,为什么呢?

通过C语言的知识我们知道:double类型的d如果要转换成int类型的i是会发生截断的,首先会用一个临时变量来保存被截断后的值,再将该值换一个新的名称,d本身是不会发生任何改变的。而这个临时变量是具有常数性的(这个很重要,后面也会反复的提及)不能被修改,也就是不能够写,只能够读。由于权限不能够升高,所以我们必须得加const才行。

我们再来回答上面的问题,引用类型和引用实体一定要是同一种类型的吗?

如果想要正确的使用,这句话显然没有什么毛病,但是并不是说引用类型和引用实体不是同一种类型程序一定就会报错。

建议:以后我们引用一个实体是如果不想改变这个实体,最好加上const.


4 使用场景

像上面举出来引用的栗子,实际工程之中基本上不会这样用,而引用的使用场景主要是下面这两方面:

  • 1. 做参数
  • 2. 做返回值

 4.1 引用做参数

举一个最简单的例子,交换两个变量,以前我们是这样做的:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

现在用引用就简单一些了:

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

 这两个函数是构成函数重载的。

另外大家还记得链表那里的二级指针吗?当初可是把我们坑惨了的,忘记了的话可以参考博主写的这篇博客:单链表

如果现在用引用那不得爽死,这里,我只给了其中一个接口,其他接口也是一样的道理:

void SLPushFront(SLNode*& phead, SLTDataType x)

{
	SLNode* newNode = SLCreat(x);
	newNode->next = phead;
	phead = newNode;
}

4.2 做返回值

我们来看下面的一个程序有没有问题:

int& fun()
{
	int a = 10;
	return a;
}
int main()
{
	int ret = fun();
	cout << ret << endl;
	return 0;
}

我们运行一下程序:

 好像没有啥问题,但是我们再小小的修改一下程序:

 为啥我就加了一个cout输出一堆字符,但是我ret的结果就变成了一堆垃圾数了呢?

我们知道a是一个局部变量,出了作用域就要被销毁,再销毁前我们将a的引用用了一个临时引用变量来保存(假设这个临时变量为tmp(类型是int&)),我们发现tmp和ret都是变量a的别名,而a出了作用域就被释放了,没有加cout输出一堆字符时我们发现结果正确只是因为释放过了空间后a还没有被改变,当为cout重新建立栈帧的时候a已经被修改了,这种返回局部变量的引用是一件极其危险的事情。

但是这样修改一下就不会担心出现这种问题了:

int& fun()
{
	static int a = 10;
	return a;
}

加一个static就不会出现这种问题了。

注意: 如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
我们再来看下面一个题:
int At(int i)
{
	static int a[10];
	return a[i];
}

int main()
{
	for (int i = 0; i < 10; i++)
	{
		At(i) = 10 + i;
	}

	for (int i = 0; i < 10; i++)
	{
		cout << At(i) << " ";
	}
	cout << endl;

	return 0;
}

这个程序有问题吗?我们运行一下:

 程序报错了,为啥呢?

通过C语言的学习我们知道,传值返回是返回的一个临时变量,该变量具有常属性(只能读,不能够被写)也就是只能够作为右值,不能够作为左值,上面的第一个for循环时对其进行写操作,当然会报错,正确的处理方式是用引用返回:

 为啥引用返回是正确的呢?由于引用只是给a[i]取了一个别名,a[i]是具有读写功能的,所以就不会报错了。


5 传值、传引用效率比较

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

 我们可以来测试一下:

做参数:

#include <time.h>
struct A { int a[100000]; };
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;
}

 做返回值:

struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{
	// 以值作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc1();
	size_t end1 = clock();
	// 以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc2();
	size_t end2 = clock();
	// 计算两个函数运算完成之后的时间
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

 通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大


 6 引用和指针的区别

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

底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

 我们来看下引用和指针的汇编代码对比:

 引用和指针的不同点:

1. 引用 在定义时 必须初始化 ,指针没有要求
2. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型实体
3. 没有 NULL 引用 ,但有 NULL 指针
4. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32 位平台下占4 个字节 )
5. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全

7 总结

本文主要介绍了引用的概念,怎样使用引用以及引用的使用场景,还举了很多容易出错的栗子来帮助理解引用,最后列举了引用和指针的区别。如果该文对你友帮助的话能不能3连支持已选博主呢?

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

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

相关文章

Java+Swing+mysql会员卡管理系统

JavaSwingmysql会员卡管理系统一、系统介绍二、功能展示1.主页页面2.会员信息查询3.会员信息删除三、系统实现1.members.java四、其它1.其他系统实现一、系统介绍 使用 Java 技术开发一个会员卡管理系统&#xff0c;具体实现功能如下&#xff1a; 1. 程序启动显示主界面&#…

Vue:从组件开始学习

文章目录Vue组件生命周期根据官网文档&#xff0c;我们可以快速使用vue3创建自己的应用代码&#xff1a;npm init vuelatest&#xff0c;然后根据自己的需要来选择对应的配置&#xff1a; 默认使用vite来配置项目的。 在main.ts入口文件中&#xff0c;我们可以看到&#xff0…

非零基础自学Golang 第17章 HTTP编程(上) 17.5 知识拓展

非零基础自学Golang 文章目录非零基础自学Golang第17章 HTTP编程(上)17.5 知识拓展17.5.1 curl工具详解第17章 HTTP编程(上) 17.5 知识拓展 17.5.1 curl工具详解 【1】curl 简介 curl是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;于1997年首次发行。它支持文…

Java+MySQL基于ssm的互助救援车队管理系统

此项目能够更全面的为社会贡献爱心&#xff0c;更及时的帮助求助人&#xff0c;然后在后台完成整个过程最后在通过广播好人好事&#xff0c;在高考爱心送子、养老院奉献爱心等活动更能做到统一化&#xff0c;更有序让注册的私家车主有的放矢&#xff0c;供献爱心。现在社会的信…

MyBatis-Plus(实用篇)

文章目录一、基础组件&#xff08;接口和实现类&#xff09;1、BaseMapper\<T>2、IService\<T>3、链式查询与修改4、调用Service层操作数据二、常用注解1、TableName2、TableId3、TbaleField4、TableLogic三、条件构造器1、wapper介绍2、构造器常用方法3、组装条件…

编程艺术之变成原则

编程有一个原则&#xff0c;就是尽可能去避免重复的代码。 类的开闭原则&#xff0c;类做好后&#xff0c;就尽量不要再在类上面在修改代码&#xff0c; 耦合度&#xff1a;简单的一个例子&#xff0c;活字印刷术在之前是整版印刷&#xff0c;导致&#xff0c;如果有一个字要…

作一回白嫖怪:写一个脚本自动获取ST官网积分,用积分领取奖品

环境&#xff1a;Python、selenium、ubuntu22.04 网址&#xff1a;STMCU中文官网 chrome: 版本 108.0.5359.124&#xff08;正式版本&#xff09; &#xff08;64 位&#xff09; chromeDriver: CNPM Binaries Mirror 这两个文件我打包起来了&#xff0c;0积分方便大家…

【表格合并与底纹】vue-elementul表格简单实现合并单元格,与列和行给底纹颜色

前言 这是一个很常见的需求啊&#xff0c;因为很多公司都会涉及到写表格展示数据 那么在某些公司内就会出现为了让数据更直观的感受到 而让你给某些行和列用颜色标出来。使得看起来更方便 那么这里就汇总一下常用的横竖合并以及横竖颜色底纹如何实现 效果图 这是写的一个dem…

小米便签维护过程记录——可能出现问题解决方案

在对小米便签开源代码进行研究和维护及新功能开发的同时&#xff0c;会遇到很多问题&#xff0c;将以本文进行记录总结。 导入项目 若不导入直接Open会导致默认为Project&#xff0c;不为Android。 小米标签菜单栏不显示的问题 先来看NotesListActivity类&#xff0c;这个类创…

Zookeeper 4 Zookeeper JavaAPI 操作 4.5 Curator API 常用操作【修改节点】

Zookeeper 【黑马程序员Zookeeper视频教程&#xff0c;快速入门zookeeper技术】 文章目录Zookeeper4 Zookeeper JavaAPI 操作4.5 Curator API 常用操作4.5.1 修改节点4 Zookeeper JavaAPI 操作 4.5 Curator API 常用操作 4.5.1 修改节点 直接开干 修改之前app1 的数据是本机…

PS1文件执行

PS1文件执行目录概述需求&#xff1a;设计思路实现思路分析1.power shell 管理2.shell 管理执行参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for ch…

软件需求说明书(GB856T——88)基于协同的在线表格forture-sheet

软件需求说明书的编写提示 1引言 1.1产品目的 制造一个功能丰富&#xff0c;配置简单的在线表格组件&#xff0c;开箱即用&#xff0c;产品对位所有办公用户&#xff0c;可以大量用户同时在线进行协同合作办公&#xff0c;可以大大的提高工作效率。 1.2产品范畴 产品为软件…

Javaweb会话跟踪技术(Cookie和Session)

目录 一、会话跟踪技术概述 二、Cookie 1.Cookie基本原理 2.Cookie基本使用 3.Cookie存活时间 4.cookie存储中文 三、Session 1.Session钝化、活化 2.Session基本使用 3.sesion销毁 四Cookie和Sesion区别 一、会话跟踪技术概述 1.会话&#xff1a;用户打开浏览器&…

Java和vue开发的橱柜定制系统家具定制系统

简介 橱柜定制家具定制系统。用户查看家具样本&#xff0c;进行预约下单&#xff0c;后台人员根据用户的要求给出效果图和方案&#xff0c;以及报价&#xff0c;填写上门时间。管理员上门测量和用户确定好需求后上传协议&#xff0c;此时订单变成待开工订单&#xff0c;后台人…

过半985、单岗位2K+简历!速腾聚创如何开展校园招聘?

在半导体、芯片等新兴科技产业&#xff0c;人才短缺和人才培养已经成为全球性问题。 速腾聚创是国内激光雷达领域的龙头企业&#xff0c;在庞大人才实力的助推下&#xff0c;构建起激光雷达硬件、感知软件和芯片三大核心技术闭环&#xff0c;通过领先的技术实力和过硬的产品质量…

VB实现火焰的效果

Option Explicit 锁定指定窗口&#xff0c;禁止它更新。同一时刻间只能有一个窗口处于锁定状态&#xff0c;可用在界面作大弧度布局改变时。 Private Declare Function LockWindowUpdate Lib “user32” (ByVal hwndLock As Long) As Long 在指定的设备场景中设置一个像素的RGB…

机器学习多分类二分类回归问题数据集分享

数据集&#xff1a; https://download.csdn.net/download/qq_38735017/87336921

DocuWare 文档管理软件在医疗保健行业的应用

DocuWare 文档管理软件在医疗保健行业的应用 尽管技术在其他领域取得了很大进步&#xff0c;但许多医院、门诊机构和医疗保健提供商仍然使用过时的系统来管理计费、财务和人力资源等文档密集型流程。借助快速、安全、灵活的 DocuWare 文档管理软件&#xff0c;可以节省您的时间…

基于注解方式实现Spring Security忽略拦截

文章目录1.Spring Security忽略拦截配置2.基于配置文件注入2.1.添加配置2.2.修改Spring Security配置类2.3. 测试3.基于注解的方式过滤接口3.1.添加忽略拦截注解3.2.获取所有使用了IgnoreWebSecurity注解的接口访问路径3.3.测试1.Spring Security忽略拦截配置 关于Spring Secu…

启动项目端口被占用无奈只能重启?程序员的电脑绝不允许重启!

各位小伙伴大家好呀~最近疫情严重很多小伙伴都阳了༼༎ຶᴗ༎ຶ༽虽然放开了&#xff0c;但还是要注意防护呀&#xff01; 我们在写代码的时候&#xff0c;很多小伙伴都遇到过启动项目但是端口被占用&#xff0c;找了半天也不知道究竟谁占用的&#xff0c;所以就使出了“杀手锏…