【c++】深入理解别名机制--引用
🌟🌟作者主页:ephemerals__
🌟🌟所属专栏:C++
目录
前言
一、引用的概念和定义
二、引用的特性
三、引用的实用性
1.引用传参
2.引用做返回值
2.1 引用做返回值的作用
2.2 引用坍缩问题、悬挂引用问题
四、const修饰引用
五、引用和指针的联系
总结
前言
我们都知道,在c语言中,指针是一种功能十分强大的数据类型,它允许我们直接访问并且操作内存。然而,它在使用时稍有不慎,就会出错。对此,c++引入了一个新的概念:引用。引用可以实现部分类似于指针的功能,并且它比指针更加安全、简洁。
一、引用的概念和定义
引用,作为c++中的一种特殊别名机制,当我们定义引用时,并不是创建了一个新变量,而是
给原有的变量起了一个别名。它的定义方式如下:
(数据类型)& 引用名 = 引用对象;
代码举例:
#include <iostream>
using namespace std;int main()
{int a = 0;int& b = a;//定义引用,给a取了一个别名a++;cout << b << endl;b++;cout << a << endl;return 0;
}
运行结果:
可以看到,无论是对a自增,还是对b自增,它们表示的值都会发生改变。我们再来打印一下它们的地址:
cout << &a << endl;
cout << &b << endl;
结果显示它们的地址是相同的。这表明引用只是给变量起了一个别名,表示的还是同一块内存空间。
我们画图表示一下引用:
二、引用的特性
引用有以下三点语法特性:
1.引用在定义的时候必须要表明它所表示的对象。
2.由于引用是用作给变量取别名,所以一个变量可以有多个引用。当然,引用也可以有引用。
3.引用一旦指定了对象,就不能再指定其他对象。
三、引用的实用性
了解的引用的概念和特性之后,我们不禁会发出疑问:既然要对变量进行操作,直接修改不就好了嘛,何必还要取一个别名呢?
1.引用传参
举一个例子:
#include <iostream>
using namespace std;void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}int main()
{int a = 3;int b = 5;Swap(a, b);//交换a和b的值cout << "a = " << a << endl;cout << "b = " << b << endl;return 0;
}
运行结果:
可以看到,使用引用传参,通过函数交换了变量a和b的值。由于引用是给变量起别名,所以此时的x和y就表示a和b本身。因此,我们在函数内部就实现了这两个元素的交换。相比传址调用,它的写法更加简单,并且在语法层面,引用是不开辟新内存的,减少了拷贝,节省了内存空间。
2.引用做返回值
2.1 引用做返回值的作用
首先来看一段代码:
#include <iostream>
using namespace std;int fun()
{static int a = 10;return a;
}int main()
{fun()++;//报错cout << fun() << endl;return 0;
}
很显然,以上代码是不可行的。函数的返回值是一个临时变量,而临时变量具有常性,我们无法对这个值进行修改。但是引用做返回值可以做到这一点:
#include <iostream>
using namespace std;int& fun()
{static int a = 10;return a;
}int main()
{fun()++;cout << fun() << endl;return 0;
}
我们将返回值改成int的引用类型,则此时函数返回静态变量a的别名,所以我们让它自增,就相当于改变了a的值。
有了引用做返回值,我们在调用函数的时候就可以通过这个返回值直接访问和修改原始对象,并且避免了临时变量的拷贝,增加程序运行的效率。
2.2 引用坍缩问题、悬挂引用问题
刚才引用做返回值的方法虽然好用,但是难免会出现一些问题。举个例子:
#include <iostream>
using namespace std;int& func1()
{static int a = 0;return a;
}int main()
{int x = func();return 0;
}
虽然这里的func1函数返回了a的引用,但是我们却在主函数中以一个整形变量来接收,这里就会发生一种隐式的类型转换--引用坍缩,编译器会将这个返回值转换为它所引用的对象的一个临时拷贝,这将导致我们无法访问并修改a的值,达不到预期效果。所以一定要以相同类型的引用来接收引用返回值。
再举一个例子:
#include <iostream>
using namespace std;int& func2()
{int a = 0;return a;
}int main()
{int& x = func();return 0;
}
在func2函数中,我们创建了一个局部变量a并且返回它的引用,但是由于a是一个局部变量,当函数栈帧销毁时,变量a的空间已经被释放了,此时的返回值就变成一个悬挂引用(野引用),也就是说这个引用的主体已经不存在了,程序的运行结果就是未定义的。所以我们在使用引用做返回值时,一定要注意返回后的引用主体是否还存在。
四、const修饰引用
我们在定义引用时,可以在变量名之前加上const修饰(称之为常引用)。当一个引用被const修饰时,该引用就无法修改其所表示的对象。例如:
#include <iostream>
using namespace std;int main()
{int a = 0;const int& b = a;a = 10;b = 20;//报错return 0;
}
注意:对于一个被const修饰的变量,定义它的引用时也需要用const修饰。例如:
#include <iostream>
using namespace std;int main()
{const int a = 0;int& b = a;//报错const int& c = a;//正确return 0;
}
对于以下情况,定义引用时也必须要用const修饰:
#include <iostream>
using namespace std;int main()
{int a = 5;const int& b = a * 3;//a*3是一个临时对象,具有常性,它的引用要用const修饰float c = 5.5f;const int& d = c;//当引用和对象的类型不同时,由于隐式类型转换的结果是一个临时对象,定义引用也需要用const修饰return 0;
}
五、引用和指针的联系
引用和指针是相辅相成的,它们能够实现对方的部分功能,但是又不可完全替代。它们的一些联系和区别如下:
1.从语法层面上,引用是对一个对象取别名,不会开辟空间;而指针用于存储一个对象的地址,会开辟空间。
2.定义引用时,必须要指定表示的对象;而指针在定义时可以不指向对象。
3.引用不能改变表示的对象,而指针可以改变。
4.由于引用是对象的别名,所以可以直接通过引用访问对象;而指针则需要解引用才能访问对象。
5.相比指针,引用在使用上更加安全,不容易出现悬挂引用的问题。
6.在某些情况下,指针和引用在语义上可以相互替代,例如函数传参,都可以形成数据共享,并且避免内存的过度消耗。
总结
今天,我们学习了引用。引用的功能十分强大,同时也弥补了指针的一些不足。深入理解引用对我们之后学习并实现类的相关功能有很大帮助。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤
相关文章:

【c++】深入理解别名机制--引用
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C 目录 前言 一、引用的概念和定义 二、引用的特性 三、引用的实用性 1.引用传参 2.引用做返回值 2.1 引用做返回值的作用 2.2 引用坍缩问题、悬挂引用问…...

简便的qemu img扩容方法
虚拟机用着用着磁盘空间就不够了,那就要想办法增加磁盘空间大小 了。在虚拟机本身磁盘的基础上直接增加空间大小最简便,于是记录一下方法。 首先,在虚拟机关机状态下,使用qemu-img命令给虚拟机的磁盘镜像增加虚拟空间5GBÿ…...

EPERM: operation not permitted,
这个错误提示 EPERM: operation not permitted, mkdir C:\Program Files\nodejs\node_global\node_modules\pnpm_tmp 通常是因为权限不足导致的。在 Windows 系统中,C:\Program Files\ 目录通常需要管理员权限才能写入。 要解决这个问题,你可以尝试以下…...

将Centos 8 Linux内核版本升级或降级到指定版本
本文以centos 8.0为例,内核版本为4.18.0-80.el8.x86_64,升级到内核版本为4.18.0-80.4.2.el8_0.x86_64。 1.查看当前系统版本信息 [rootcentos80-1905 ~]# uname -sr Linux 4.18.0-80.el8.x86_642.在网站:https://vault.centos.org/里面下载…...

小程序商城被盗刷,使用SCDN安全加速有用吗?
在电子商务蓬勃发展的今天,小程序商城因其便捷性和灵活性成为商家和消费者的新宠。然而,随着其普及,小程序商城的安全问题也日益凸显,尤其是盗刷现象频发,给商家和用户带来了巨大损失。面对这一挑战,是否可…...

nginx的基本使用与其日志
文章目录 1.nginx编译安装脚本2.nginx平滑升级,以及其步骤3.nginx核心配置,及实现nginx多虚拟主机4.nginx日志格式定制5.nginx反向代理及https安全加密6.基于LNMP和Redis的phpmyadmin的会话保持,以及其完整步骤 1.nginx编译安装脚本 #编译安…...

linux | 苹果OpenCL(提高应用软件如游戏、娱乐以及科研和医疗软件的运行速度和响应)
点击上方"蓝字"关注我们 01、引言 >>> OpenCL 1.0 于 2008 年 11 月发布。 OpenCL 是为个人电脑、服务器、移动设备以及嵌入式设备的多核系统提供并行编程开发的底层 API。OpenCL 的编程语言类似于 C 语言。其可以用于包含 CPU、GPU 以及来自主流制造商如 …...

算法-UKF中Sigma点生成
void UKF::MakeSigmaPoints() {Eigen::VectorXd x_aug_ Eigen::VectorXd(n_x_);x_aug_.head(n_x_) x_;Eigen::MatrixXd P_aug Eigen::MatrixXd::Zero(n_x_, n_x_);// 转成正定矩阵P_aug pdefinite_svd(P_);// LLT分解Eigen::MatrixXd L P_aug.llt().matrixL();sigma_point…...

精选五款热门骨传导耳机分享,让你避免踩坑的陷阱
因为骨传导耳机独特的佩戴方式和声音的传播方式,受到了小耳、油耳以及运动爱好者的的喜爱,但也由于市面上的骨传导耳机品牌越来越多,很多朋友不知道该怎么选择,今天我挑选出市面上体验感较好,各方面比较出色的骨传导给…...

「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)
概述 为什么大家总觉得KMP难?难的根本就不是这个算法本身。 在互联网上你可以见到八十种KMP算法的next数组定义和模式串回滚策略,把一切都懂得特别混乱。很多时候初学者的难点根本不在于这个算法本身,而是它令人痛苦的百花齐放的定义。 有…...

python人工智能002:jupyter基本使用
小知识:将jupyter修改为中文,修改用户变量, 注意是用户变量,不是系统变量 新增用户变量 变量名:LANG 变量值:zh_CN.UTF8 然后重启jupyter 上一章的软件安装完成之后,就可以创建文件夹来学习写…...

Linux使用 firewalld管理防火墙命令
Linux 发行版中使用的动态防火墙管理工具。使用 firewalld,你可以查看防火墙状态、当前配置的规则以及开放的端口。以下是一些常用的 firewalld 命令来管理和查看防火墙状态及端口配置。 1. 查看防火墙状态 检查 firewalld 是否正在运行 sudo systemctl status f…...

二叉树(三)
一、二叉树的遍历 二叉树遍历是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。 1.前序遍历(先根遍历) 前序遍历(Preorder Traversal也叫先序遍历)——根、左子树、右…...

05--kubernetes组件与安装
前言:终于写到kubernetes(k8s),容器编排工具不止k8s一个,它的优势在于搭建集群,也是传统运维和云计算运维的第一道门槛,这里会列出两种安装方式,详细步骤会在下文列出,文…...

EmguCV学习笔记 VB.Net和C# 下的OpenCv开发 C# 目录
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…...

探索TensorFlow:深度学习的未来
标题:探索TensorFlow:深度学习的未来 在当今快速发展的人工智能领域,TensorFlow无疑是最耀眼的明珠之一。TensorFlow是由Google Brain团队开发的一个开源机器学习框架,它以其强大的灵活性、易用性和高效的性能,迅速成…...

探索地理空间分析的新世界:Geopandas的魔力
文章目录 探索地理空间分析的新世界:Geopandas的魔力背景:为何选择Geopandas?这个库是什么?如何安装这个库?五个简单的库函数使用方法场景应用:Geopandas在实际工作中的应用常见bug及解决方案总结 探索地理…...

如何为网站申请免费SSL证书?
一、准备阶段 确定证书类型: 对于大多数个人博客和小型企业网站,DV(域名验证)SSL证书已足够使用,因为它仅验证域名所有权,成本较低且验证快速。准备域名: 确保你拥有一个有效的域名,…...

Java项目集成RocketMQ
文章目录 1.调整MQ的配置1.进入bin目录2.关闭broker和namesrv3.查看进程确认关闭4.编辑配置文件broker.conf,配置brokerIP15.开放端口109116.重新启动1.进入bin目录2.启动mqnamesrv和mqbroker1.启动 NameServer 并将输出重定向到 mqnamesrv.log2.**启动 Broker 并将…...

如何将 Bamboo agent 能力迁移到极狐GitLab tag 上?
极狐GitLab 是 GitLab 在中国的发行版,专门面向中国程序员和企业提供企业级一体化 DevOps 平台,用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规,而且所有的操作都是在一个平台上进行,省事省心省钱。可以一键安装极狐GitL…...

正则表达式入门:Python ‘ re ‘ 模块详解
正则表达式(Regular Expression,简称 re)是一种强大而灵活的工具,广泛用于字符串匹配、替换和分割等操作,尤其在处理网页爬虫数据时非常有用。Python 提供了 " re " 模块来支持正则表达式的使用,…...

thinkphp8.0+aliapy(支付宝)pc网站支付
环境:宝塔-centOS8.5,php8.3 第一步:安装alipay v3版本的安装依赖包; composer require alipaysdk/openapi:dev第二步:根据官方文档,把支付相关的类引用进来; <?php declare (strict_types 1);namespace app\p…...

高速信号的眼图、加重、均衡
目录 高速信号的眼图、加重、均衡眼图加重均衡线性均衡器CTLE判决反馈均衡器DFE 高速信号的眼图、加重、均衡 眼图 通常用示波器观察接收信号波形的眼图来分析码间串扰和噪声对系统性能的影响,从而估计系统优劣程度,因而眼图分析是高速互连系统信号完整…...

2024年PMP考前冲刺必背的学习笔记,整理好给你!
项目的四大特点:临时性、独特性、变革驱动性和创造商业价值。 项目管理:将知识、技能、工具与技术应用于项目活动,以满足项目的要求 Pestle:P政治,E经济,S社会,T技术,L法律,E环境 …...

增加服务器带宽可以提高资源加载速度吗?
答案是可以的 ,增加服务器带宽通常能够提高资源加速速度。带宽是服务器与互联网之间传输数据的速率,它决定了在单位时间内可以传输的数据量。以下是增加带宽如何提高资源加速速度的几个方面: 1.更快的数据传输:带宽增加后…...

汽车EDI: NAVISTAR EDI对接
Navistar International Corporation 是一家美国商用车辆制造公司,总部位于伊利诺伊州的Lisle。公司以生产中型和重型卡车、公共汽车、柴油发动机和底盘闻名,其产品广泛应用于运输、建筑、和农业等行业。Navistar 的历史可以追溯到1831年,由国…...

【Word多级标题完整设置】设置各级标题样式将多级列表链接到各级标题样式中
Word多级标题完整设置 一、设置各级标题样式主标题样式设置中英文字体、字形以及字号设置段落设置(缩进、间距和行距) 一级标题样式设置中英文字体、字形以及字号设置段落设置(缩进、间距和行距) 二级标题样式设置中英文字体、字形…...

不同分辨率下vue页面的高度自适应
1. 使用视口单位 .element { height: 100vh; /* 使得元素高度等于视口高度的100% */ /* 可以减去一部分高度以适应页眉或页脚 */ height: calc(100vh - 100px); } 2. 使用百分比(%)高度 .parent { height: 100vh; /* 父元素高度等于视口高度 */…...

“野生钢铁侠 “ 稚晖君一连亮出5 款智元人形机器人,地表最强!
打麻将、拆快递、纽扣穿针,还能做 30KG 重物提拉! 沉寂一年,稚晖君带着他的二代机器人全家桶重磅回归,秀出的各种新技能令人眼前一亮。 智东西 8 月 18 日报道,今日," 野生钢铁侠 " 稚晖君一连亮…...

JSON Web Token (JWT): 理解与应用
JWT(JSON Web Token)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的,因为它可以使用JSON对象在各方…...