C++系列-引用

news2024/12/27 1:21:24

引用

  • 引用的基本使用
    • 引用的起源
    • 引用的语法
    • 引用的本质
    • 引用的注意事项
    • 引用和指针
  • 引用作为函数参数
  • 引用作为函数的返回值
  • 常量引用
  • 其它
    • 用返回值方式调用函数(case 1)
    • 用函数的返回值初始化引用的方式调用函数(case 2)
    • 用返回引用的方式调用函数(case3)
    • 用函数返回的引用作为新引用的初始化值的方式来调用函数(case4)

引用的基本使用

引用的起源

  • 将变量名作为实参:值传递,改变形参,实参并不改变。
  • 将指针作为实参:实际上采用的也是值传递,只不过这里的值指的是变量的地址。
  • 传送变量的别名:传递的是变量的地址,所以二者本身完全是同一个地址的变量。

引用的语法

  • 数据类型 &别名=变量名
  • & 引用声明符,别名和原变量代表的是同一变量单元
  • 在传参数时,别名和原变量可以取同一个名字

引用的本质

  • 给变量起别名。
  • 引用的本质是一个指针常量(int * const p =&a;是个指针,该指针是常量)
  • 指针常量的指向不可更改,但是该地址内的值可以更改,这就是引用一旦初始化为某一变量的别名后,再不能更改的原因。

在这里插入图片描述

  • 在外部看,可以简化如下:

在这里插入图片描述

	code:
	#include <iostream>
	#include <string>
	using namespace std;
	int main()
	{
		int a = 666;
		int& b = a;		// 编译器内部自动转化为	int* const b = & a;
		b = 888;		// 发现是引用,自动转化为 *b=888;
		cout << "a的值:" << a << endl;
		system("pause");
	}
result:

引用的注意事项

  • 引用在声明时,必须同时初始化。
  • 必须引用合法的内存空间(int &a=10; 错的)。
  • 在声明一个变量的引用后,不能再作为其它变量的别名。
code:
	int a = 10;
	cout << "address of a:" << &a << ", value of a:" << a << endl;
	int x = 20;
	cout << "address of x:" << &x << ", value of x:" << x << endl;
	int & b = a;	//引用声明
	
	cout << "address of b:" << &b << ", value of b:" << b << endl;
	b = x;			//是变量赋值,而不是将该引用作为其它变量的引用	
	cout << "address of a:" << &a << ", value of a:" << a << endl;
	cout << "address of b:" << &b << ", value of b:" << b << endl;	

result:
	address of a:000000D209FCFB34, value of a:10
	address of x:000000D209FCFB54, value of x:20
	address of b:000000D209FCFB34, value of b:10
	address of a:000000D209FCFB34, value of a:20		// a的值变为20
	address of b:000000D209FCFB34, value of b:20

引用和指针

  • 不必设立指针变量,指针变量要开坡另外的内存空间,其内容是地址。二引用变量不是第一个独立的变量,不单独占用内存空间。
  • 在函数调用时,并不需要再变量名前加取址符。
  • 在&a前面有类型时,是引用,如 int &a, 否则为取址符。
  • 改变形参,对于引用和指针,实参同时改变。

引用作为函数参数

  • 引用作为函数形参,形参改变,实参改变。
  • 不需要像指针那么复杂的操作。
值传递仅仅改变形参,实参不发生变化
code:
#include <iostream>
#include <string>
using namespace std;

void swap(int x, int y)
{
	cout << "值传递swap之前:x, y分别为: " << x << "," << y << endl;
	int temp;
	temp = x;
	x = y;
	y = temp;
	cout << "值传递swap之后:x, y分别为: " << x << "," << y << endl;
}

int main()
{
	int a1 = 666;
	int b1 = 888;
	cout << "值传递swap之前:a1, b1分别为: " << a1 << "," << b1 << endl;
	swap(a1, b1);
	cout << "值传递swap之后:a1, b1分别为: " << a1 << "," << b1 << endl;
	system("pause");
	return 0;
}

result:
	值传递swap之前:a1, b1分别为: 666,888
	值传递swap之前:x, y分别为: 666,888
	值传递swap之后:x, y分别为: 888,666
	值传递swap之后:a1, b1分别为: 666,888
指针作为参数,传递的是实参的地址值,那么对该地址的操作,会影响到实参。
code:
#include <iostream>
#include <string>
using namespace std;

void swap_pt(int *x, int *y)
{
	cout << "x, y地址分别为: " << x << "," << y << endl;
	cout << "值传递swap之前:*x, *y分别为: " << *x << "," << *y << endl;
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
	cout << "值传递swap之后:*x, *y分别为: " << *x << "," <<* y << endl;
}

int main()
{
	int a1 = 666;
	int b1 = 888;
	cout << "a1, b1地址分别为: " << &a1 << "," << &b1 << endl;
	cout << "值传递swap之前:a1, b1分别为: " << a1 << "," << b1 << endl;
	swap_pt(&a1, &b1);
	cout << "值传递swap之后:a1, b1分别为: " << a1 << "," << b1 << endl;
	system("pause");
	return 0;
}

result:
	a1, b1地址分别为: 00000006F5D4F904,00000006F5D4F924
	值传递swap之前:a1, b1分别为: 666,888
	x, y地址分别为: 00000006F5D4F904,00000006F5D4F924
	值传递swap之前:*x, *y分别为: 666,888
	值传递swap之后:*x, *y分别为: 888,666
	值传递swap之后:a1, b1分别为: 888,666
引用传递,实参和形参是同一变量
code:
#include <iostream>
#include <string>
using namespace std;

void swap_reference(int &x, int &y)
{
	cout << "x, y地址分别为: " << &x << "," << &y << endl;
	cout << "引用传递swap之前:x, y分别为: " << x << "," << y << endl;
	int temp;
	temp = x;
	x = y;
	y = temp;
	cout << "引用传递swap之后:x, y分别为: " << x << "," << y << endl;
}

int main()
{
	int a1 = 666;
	int b1 = 888;
	cout << "a1, b1地址分别为: " << &a1 << "," << &b1 << endl;
	cout << "引用传递swap之前:a1, b1分别为: " << a1 << "," << b1 << endl;
	swap_reference(a1, b1);
	cout << "引用传递swap之后:a1, b1分别为: " << a1 << "," << b1 << endl;
	system("pause");
	return 0;
}

result:
	a1, b1地址分别为: 0000003871CFFB14,0000003871CFFB34
	引用传递swap之前:a1, b1分别为: 666,888
	x, y地址分别为: 0000003871CFFB14,0000003871CFFB34
	引用传递swap之前:x, y分别为: 666,888
	引用传递swap之后:x, y分别为: 888,666
	引用传递swap之后:a1, b1分别为: 888,666

引用作为函数的返回值

  • 要返回局部变量的引用。
  • 如果函数的返回是个引用,则函数的调用可以作为左值。
  • 不能返回函数内部通过new分配的内存的引用。
//不要返回局部变量的引用,局部变量在栈区,调用完毕后释放,有可能第一次使用该引用时,编译器可能还没释放,但是后面会出错
code:
	#include <iostream>
	#include <string>
	using namespace std;
	
	int & test()
	{
		int x = 100;
		return x;
	}
	
	int main()
	{
		int& ref = test();
		cout << "ref的值1:" << ref << endl;
		cout << "ref的值2:" << ref << endl;
		system("pause");
	}
result:
	ref的值1:632365056
	ref的值2:632365056
code:
	#include <iostream>
	#include <string>
	using namespace std;
	
	
	int& test_static()
	{
		static int x = 0;
		x += 666;
		return x;
	}
	
	int main()
	{
		int& ref = test_static();		// ref是函数中x的别名
		test_static() = 2000;			// test_static()返回的就是x的别名,相当对x=2000,
		cout << "ref的值:" << ref << endl;
		system("pause");
	}

result:
	ref的值:2000

常量引用

  • 可以用于形参,防止误操作。
	code:
	#include <iostream>
	#include <string>
	using namespace std;
	
	int main()
	{
		int a = 666;
		//int& b = 888;			// 报错,必须引用合法的内存空间,888都不知道地址是什么
		const int &b = 888;		// 自动转化为 int temp = 888; const int &b = temp; 只能使用别名
		//b = 30;				// 不可再修改
		cout << "b的值:" << b << endl;
		system("pause");
	}
code:
	#include <iostream>
	#include <string>
	using namespace std;
	
	void print_data(const int& a)
	{
		//a = 100;		//错误,已经不可再修改
		cout << "a = " << a << endl;
	}
	
	int main()
	{
		int a = 666;
		print_data(a);
	}
result:
	a = 666

其它

code:
	#include<iostream>
	using namespace std;
	float temp;
	float fn1(float r) {
		temp = r * r * 3.14;
		return temp;
	}
	float& fn2(float r) { //&说明返回的是temp的引用,换句话说就是返回temp本身
		temp = r * r * 3.14;
		return temp;
	}
	int main() {
		float a = fn1(5.0);			//case 1:返回值
		//float &b=fn1(5.0);		//case 2:用函数的返回值作为引用的初始化值 [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
									//(有些编译器可以成功编译该语句,但会给出一个warning) 
		float c = fn2(5.0);			//case 3:返回引用	
		float& d = fn2(5.0);		//case 4:用函数返回的引用作为新引用的初始化值
		cout << a << endl;//78.5
		//cout<<b<<endl;//78.5
		cout << c << endl;//78.5
		cout << d << endl;//78.5
		system("pause");
		return 0;
	}

用返回值方式调用函数(case 1)

  • 返回全局变量temp的值时,C++会在内存中创建临时变量并将temp的值拷贝给该临时变量。
  • 当返回到主函数main后,赋值语句a=fn1(5.0)会把临时变量的值再拷贝给变量a。
    在这里插入图片描述

用函数的返回值初始化引用的方式调用函数(case 2)

  • 函数fn1()是以值方式返回时,首先拷贝temp的值给临时变量。返回到主函数后,用临时变量来初始化引用变量b,使得b成为该临时变量到的别名。
  • 由于临时变量的作用域短暂(在C++标准中,临时变量或对象的生命周期在一个完整的语句表达式结束后便宣告结束,也就是在语句float &b=fn1(5.0);之后) ,所以b面临无效的危险,很有可能以后的值是个无法确定的值
    在这里插入图片描述
  • 可以如下操作:
code:
	int x=fn1(5.0);		//x不释放
	int &b=x;

用返回引用的方式调用函数(case3)

  • 函数fn2()的返回值不产生副本,而是直接将变量temp返回给主函数,即主函数的赋值语句中的左值是直接从变量temp中拷贝而来(也就是说c只是变量temp的一个拷贝而非别名) ,这样就避免了临时变量的产生。
  • 尤其当变量temp是一个用户自定义的类的对象时,这样还避免了调用类中的拷贝构造函数在内存中创建临时对象的过程,提高了程序的时间和空间的使用效率。

在这里插入图片描述

用函数返回的引用作为新引用的初始化值的方式来调用函数(case4)

  • 函数fn2()的返回值不产生副本,而是直接将变量temp返回给主函数。在主函数中,一个引用声明d用该返回值初始化,也就是说此时d成为变量temp的别名。
  • 由于temp是全局变量,所以在d的有效期内temp始终保持有效,故这种做法是安全的。

在这里插入图片描述

注意:
本文中的部分内容来自伯乐在线

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

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

相关文章

No113.精选前端面试题,享受每天的挑战和学习

文章目录 怎样理解 Vue 的单向数据流说下MVVM说下cookieVue 的性能优化Cookie、localStorage 和 sessionStorageVue中的computed属性和watch属性有什么区别&#xff1f; 怎样理解 Vue 的单向数据流 在Vue中&#xff0c;单向数据流是指数据在Vue组件中的传递方向是有限制的&…

使用Vscode调试shell脚本

在vcode中安装bash dug插件 在vcode中添加launch.json配置&#xff0c;默认就好 参考&#xff1a;http://www.rply.cn/news/73966.html 推荐插件&#xff1a; shellman(支持shell,智能提示) shellcheck(shell语法检查) shell-format(shell格式化)

【文化课学习笔记】【化学】金属及其化合物

【化学】必修一&#xff1a;金属及其化合物 钠及其化合物 钠单质 物理性质 颜色&#xff1a;银白色&#xff0c;有金属光泽&#xff1b;密度&#xff1a;\(\mathrm{\rho_{H_2O}>\rho_{Na}>\rho_{煤油}}\)(钠可以在煤油中进行保存)&#xff1b;熔点&#xff1a;低于 \(100…

多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)

多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)。 一个新项目,后端使用 PHP 实现,前端不做路由,提供一个模板,由后端路由控制。 Route::get(pages/{name}, [\App\Http\Controllers\ResourceController::class, getResourceVersion])

如何在工作中利用AIGC提质增效?

引言 人工智能技术快速发展&#xff0c;以 ChatGPT 为代表的新的人工智能语言模型的出现与更迭&#xff0c;引发人们极大的兴奋和关注。越来越多的企业开始将 AI 技术应用到生产流程&#xff0c;以提高工作效率和生产力。AIGC&#xff08;AI Generated Content&#xff09;是人…

文本生成解码策略 Beam Search, top_k, temperature

一、从Greedy Search到Beam Search Greedy search是指在每个t时刻选择下一个词时&#xff0c;根据 wtargmaxwP(w|w1:t−1)选择概率最高的词。 以上图为例&#xff1a; 从单词“The”开始&#xff0c;算法在选择下一个词时&#xff0c;贪心的选择了概率最高的“nice”&#xf…

2023-8-15 差分

题目链接&#xff1a;差分 #include <iostream>using namespace std;const int N 100010;int n, m; int a[N], b[N];void insert(int l, int r, int c) {b[l] c;b[r 1] - c; }int main() {scanf("%d%d", &n, &m);for(int i 1; i < n; i)scanf…

“鸿蒙”商标被抢先注册,华为上诉失败,鸿蒙系统将被迫改名?

作为我国最著名的手机通讯企业之一&#xff0c;华为凭借着无与伦比的创新设计与可靠实用的用户体验&#xff0c;一度成为了国内最受欢迎的手机品牌。此外&#xff0c;华为手机在海外市场的销量也不遑多让&#xff0c;不仅质量优异&#xff0c;在通讯的稳定性与可靠性上&#xf…

韦东山老师 RTOS 入门课程(一)RTOS 介绍,熟悉裸机的汇编逻辑

韦东山老师 RTOS 入门课程 课程链接&#xff1a;韦东山直播公开课&#xff1a;RTOS实战项目之实现多任务系统 第1节&#xff1a;裸机程序框架和缺陷_哔哩哔哩_bilibili RTOS 介绍 裸机&#xff1a;固定顺序执行。 中断&#xff1a;可以一直专心做循环里的事情&#xff0c;直…

林【2017】

一、判断 二、单选 三、填空 四、应用 五、算法设计

C++笔记之左值与右值、右值引用

C笔记之左值与右值、右值引用 code review! 文章目录 C笔记之左值与右值、右值引用1.左值与右值2.右值引用——关于int&& r 10;3.右值引用——对比int&& r 10;和int& r 10;4.右值引用&#xff08;rvalue reference&#xff09;的概念 1.左值与右值 2.…

Jmeter 分布式性能测试避坑指南

在做后端服务器性能测试中&#xff0c;我们会经常听到分布式。那你&#xff0c;是否了解分布式呢&#xff1f;今天&#xff0c;我们就来给大家讲讲&#xff0c;在企业实战中&#xff0c;如何使用分布式进行性能测试&#xff0c;实战过程中&#xff0c;又有哪些地方要特别注意&a…

stm32单片机开关输入控制蜂鸣器参考代码(附PROTEUS电路图)

说明&#xff1a;这个buzzer的额定电压需要改为3V&#xff0c;否则不会叫&#xff0c;源代码几乎是完全一样的 //gpio.c文件 /* USER CODE BEGIN Header */ /********************************************************************************* file gpio.c* brief Thi…

【Azure API 管理】APIM如何实现对部分固定IP进行访问次数限制呢?如60秒10次请求

问题描述 使用Azure API Management, 想对一些固定的IP地址进行访问次数的限制&#xff0c;如被限制的IP地址一分钟可以访问10次&#xff0c;而不被限制的IP地址则可以无限访问&#xff1f; ChatGPT 解答 最近ChatGPT爆火&#xff0c;所以也把这个问题让ChatGPT来解答&#x…

Python可视化在量化交易中的应用(14)_Seaborn散点图

Seaborn中带回归线的散点图的绘制方法 seaborn中绘制散点图使用的是sns.scatterplot()函数&#xff1a; sns.scatterplot(x,y,hue,style,size,data,palette,hue_order,hue_norm,sizes,size_order,size_norm,markers,style_order,x_bins,y_bins,units,estimator,ci95,n_boot100…

wazuh部署

文章目录 1.ova文件获取2.VMware导入ova文件3.wazuh目录文件4.wazuh解析原理 1.ova文件获取 访问官网 https://wazuh.com/依次点击红色标注将文件下载到本地 2.VMware导入ova文件 直接打开下载到本地的ova文件 设置导入的位置和名称 初始密码账户为wazuh-user:wazuh …

手写模拟SpringBoot核心流程(一):实现极简一个SpringBoot——模拟SpringBoot启动过程

前言 Spring Boot 是一个开源的框架&#xff0c;用于简化 Spring 应用程序的开发和部署。它建立在 Spring Framework 的基础上&#xff0c;内置了web服务器——tomcat和jetty&#xff0c;使得 Spring 应用的构建变得更加快速、简单和可维护。 本文通过实现一个SpringBoot&…

Global Illumination_Exponential Variance Shadow Maps(EVSM)

最近工程中需要集成高质量阴影&#xff08;效率、效果&#xff09;&#xff0c;介于项目非循环渲染所以CSM无法使用&#xff0c;但动态建模中还需要快速增删改场景&#xff0c;阴影还必须重新生成&#xff0c;奈何之前简单SMPCF无法满足效率、效果要求&#xff0c;于是调研RVT等…

十、Linux的root用户、用户和用户组的问题

目录 1、Linux的root用户 &#xff08;1&#xff09;基础 &#xff08;2&#xff09;如何进入root模式 &#xff08;3&#xff09;如何给普通用户配置root权限&#xff1f; 注意点&#xff1a; 配置方法&#xff1a; 2、用户/用户组问题 &#xff08;1&#xff09;用户/用…

【网络安全必看】如何提升自身 WEB 渗透能力?

前言 web 渗透这个东西学起来如果没有头绪和路线的话&#xff0c;是非常烧脑的。 理清 web 渗透学习思路&#xff0c;把自己的学习方案和需要学习的点全部整理&#xff0c;你会发现突然渗透思路就有点眉目了。 程序员之间流行一个词&#xff0c;叫 35 岁危机&#xff0c;&am…