【C++】C++入门基础:引用详解

news/2024/7/23 10:46:48 标签: c++, 开发语言

本篇继续分享关于C++入门的相关知识,有关命名空间、缺省参数和函数重载的部分欢迎阅读我的上一篇文章【C++】C++入门基础详解(1)_王笃笃的博客-CSDN博客

继续我们的学习

引用

在C语言中我们接触过指针,很多人都或多或少为他感到头痛过,很多C语言的使用者包括创始人都觉得很难用,所以便创造出了引用。

1.引用的概念

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

举个例子,就比如你叫李四,同学给你起了外号叫小四,你妈妈给你取的小名叫四四,这些名字都指的是李四,这么说应该不难理解;

上代码感受一下

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

	return 0;
}

可以看到我们创建出了一个整形a,使用&符号创建了b,这里的b就是a的别名,他们公用一段内存空间。

很明显&符号在类型和定义的变量中间会被当作引用符号,否则就是取地址,我们也可以看出a和b共用同一块空间;

当我们给a和b同时++运算时

 可以看到他们都参与了运算,因为他们本质上就是对同一个数据进行操作;

可以简单的使用在两数交换之中

 可以看到传值并不会真正的实现转换,但是我们用引用的方法传参

 

 可以看到两数交换成功了。

在这里里我们在函数中用引用定义参数意义是给实参取了别名,x的别名就是a,y的别名就是b,我们对a和b进行操作实际上就是对x和y进行操作。

还有一种用C语言实现链表的场景

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}ListNode;

void Push_back(ListNode** pphead, int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode) * sizeof(int));
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{

	}
}
int main()
{
	ListNode* plist = NULL;
	Push_back(&plist, 1);
	Push_back(&plist, 2);
	Push_back(&plist, 3);
}

这里的重点是二级指针的使用,当时我在写二级指针的时候也是非常头疼,但是我我们现在学习了引用可以对上面的代码进行优化;

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}ListNode;

void Push_back(ListNode*& phead, int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode) * sizeof(int));
	if (phead == NULL)
	{
		phead = newnode;
	}
	else
	{

	}
}
int main()
{
	ListNode* plist = NULL;
	Push_back(plist, 1);
	Push_back(plist, 2);
	Push_back(plist, 3);
}

可以看到现在的phead就是plist的别名,也就是说操作phead就可以达到操作plist的目的,这样就不用再纠结二级指针的使用,同样可以达到二级指针的效果。

通过以上代码我们可以知道引用作为形参,其他函数传参时引用可以影响实参。

接下来是引用使用时需要注意的一些小细节;

2.引用的特性

使用引用的时候必须初始化

 不能说只取外号没有真正的名字,这样的用法是错误的;

同时一个变量可以被多次引用,也就是说一个人可以有很多个外号,也可以给外号取外号;

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;
	int& d = a;
	int& e = d;

	return 0;
}

这些都是可行的,虽然有很多引用但是它的底层都是对a进行操作;

还需要注意的是引用一但引用了一个实体,就不能再引用其他实体,也就是说上面的b、c、d、e不能再当作别人的外号。

 

可以看到报错说e被多次初始化,这也是C++的引用和java的引用区别,C++的引用只能引用一个实体,java的引用是可以改变指向的,这样就导致C++不能脱离指针,Java可以脱离指针。

3.引用做返回值

在刚开始认识函数时我们接触过传值返回

需要注意的是这里返回值并不是n,而是n的值 

 同时也有一种用法,但是这种用法非常危险。

那就是函数传引用返回

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

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

为什么会这种用法会非常危险呢?

我们知道调用函数时会建立栈帧,函数内部的临时变量都会在调用函数结束时失效,在这里传引用返回就相当于给没有名字的空间起了别名,类似于野指针的后果,所以这种情况输出可能会有两种情况,一种是正常输出,一种会输出随机值

 

可以看到在vs的平台下会输出1,但是下方的结果或有一个waring

 

 我们再用一段代码来解释传引用返回的影响;

int& Add(int x, int y)
{
	int c = x + y;
	return c;
}

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

以下是运行结果

 这里的原因是先用1和2调用了Add函数,并且将此次调用函数所占用的空间取了别名叫做ret,此时Add函数除了作用域后里面的数值都会被销毁,而空间还会被留下来,此时再次用2和3去调用Add,那么此次调用就会使用Add的栈帧空间,就得到了如上结果。

形象的说就是你在某一家酒店开了房,走的时候发现有东西没拿上,所以重新回房间里拿了东西,希望大家可以理解。

所以分享了以上错误的使用方式可以得到一个结论:如果函数返回时,出了函数作用域,如果返回对象没有返还给系统,则可以使用引用返回;如果已经返还给系统,则必须使用传值返回。

传引用返回在有些场景下也有着便捷的作用;

当初在学习数据结构时使用C语言完成链表是非常繁琐的

这里简单使用链表找到第i个位置的数据和修改数据

struct SeqList
{
	int* a;
	int size;
	int capacity;
};
//找到第i个位置
int SLAt(SeqList* ps, int i)
{
	assert(i < ps->size);
	return ps->a[i];
}
//修改
int SLModify(SeqList* ps, int i,int x)
{
	assert(i < ps->size);
	ps->a[i]=x;

}

可以感觉到C语言的接口非常的繁琐;

下面是C++读或修改数据的接口

 

int& SLAt(SeqList* ps, int i)
{
	assert(i < ps->size);
	return ps->a[i];
}

可以看到非常非常简单,只需要在返回类型前加上引用符号即可完成读取和修改的操作,

当然也可也全部使用引用减少拷贝的时间消耗

int& SLAt(SeqList& ps, int i)
{
	assert(i < ps.size);
	return ps.a[i];
}

通过main函数来简单使用

 这样我们既可以完成读取

也可以完成修改操作

所以引用做返回值也有它合适的场景。

以上就是本片要分享的关于C++引用的使用,如果对你有所帮助还请三连支持,感谢您的阅读。

 

 


http://www.niftyadmin.cn/n/4951898.html

相关文章

Python 潮流周刊#16:优雅重要么?如何写出 Pythonic 的代码?

你好&#xff0c;我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容&#xff0c;大部分为英文。标题取自其中两则分享&#xff0c;不代表全部内容都是该主题&#xff0c;特此声明。 本周刊由 Python猫 出品&#xff0c;精心筛选国内外的 250 信息源&#xff0c;为你挑选…

sip网络号角喇叭 sip音柱 POE供电广播音箱 ip网络防水对讲终端 sip网络功放

SV-7042TP网络号角喇叭 一、描述 SV-7042TP是我司的一款SIP网络号角喇叭&#xff0c;具有10/100M以太网接口&#xff0c;内置有一个高品质扬声器&#xff0c;将网络音源通过自带的功放和喇叭输出播放&#xff0c;可达到功率30W。SV-7042TP作为SIP系统的播放终端&#xff0c;可…

算法与数据结构(五)--树与二叉查找树

符号表的增删查操作&#xff0c;随着元素个数N的增多&#xff0c;其耗时也是线性增多的&#xff0c;时间复杂度都是O(n)&#xff0c;为了提高运算效率&#xff0c;我们学习树这种数据结构。 目录 一.树的基本定义 二.树的相关术语 三.二叉树的基本定义 四.二叉树的链表实现…

ISP(Internet Service Provider)

ISP 是互联网服务提供商&#xff08;Internet Service Provider&#xff09;的缩写&#xff0c;它指的是为个人、家庭或企业提供上网连接和其他网络服务的公司或组织。ISP 是连接用户与全球互联网的桥梁&#xff0c;它提供了各种类型的网络服务&#xff0c;包括宽带、移动网络、…

宝藏级画图工具-drawio

今天推荐一款非常好用的免费开源画图工具drawio. Drawio即可以下载安装到本地&#xff0c;也可以在线编辑&#xff0c;在线编辑网址为 https://app.diagrams.net/。 本地版下载地址为https://github.com/jgraph/drawio-desktop/releases 1、支持各类图形 Drawio可以非常便捷…

SpringMVC之入门搭建框架

文章目录 前言一、SpringMVC简介1.什么是MVC2.什么是SpringMVC3.SpringMVC的特点 二、搭建框架——HelloWorld1.创建maven工程&#xff08;web项目&#xff09;2.配置web.xml3.配置springMVC.xml4.创建请求控制器 总结 前言 基础小白第一次走进SpringMVC&#xff1a;了解什么是…

Designing_Distributed_Systems :)

Abstract 链接&#xff1a;https://pan.baidu.com/s/1Krp7dSxSPXKy33RJ3XMFUA?pwdy90a 提取码&#xff1a;y90a 一个关于分布式系统中的模式说明&#xff0c;并且在K8s中上手实践。 非常好的一本书。英文版本阅读哈哈哈。On the other hand In a distant future, the world w…

【福建事业单位-公共基础-哲学】02唯物辩证法三大规律、认识论、历史唯物主义

【福建事业单位-公共基础-哲学】02唯物辩证法 一、唯物辩证法1.1 对立统一规律方法论 矛盾的不平衡性分析方法论&#xff08;两点论和重点论&#xff09;事物发展的内因和外因 1.1总结1.2 质量互变规律量变和质变的关系 方法论 1.3 否定之否定规律总结 二、认识论2.1实践决定认…