当前位置: 首页 > news >正文

【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++】深入理解别名机制--引用

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C 目录 前言 一、引用的概念和定义 二、引用的特性 三、引用的实用性 1.引用传参 2.引用做返回值 2.1 引用做返回值的作用 2.2 引用坍缩问题、悬挂引用问…...

简便的qemu img扩容方法

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

EPERM: operation not permitted,

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

将Centos 8 Linux内核版本升级或降级到指定版本

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

小程序商城被盗刷,使用SCDN安全加速有用吗?

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

nginx的基本使用与其日志

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

精选五款热门骨传导耳机分享,让你避免踩坑的陷阱

因为骨传导耳机独特的佩戴方式和声音的传播方式&#xff0c;受到了小耳、油耳以及运动爱好者的的喜爱&#xff0c;但也由于市面上的骨传导耳机品牌越来越多&#xff0c;很多朋友不知道该怎么选择&#xff0c;今天我挑选出市面上体验感较好&#xff0c;各方面比较出色的骨传导给…...

「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)

概述 为什么大家总觉得KMP难&#xff1f;难的根本就不是这个算法本身。 在互联网上你可以见到八十种KMP算法的next数组定义和模式串回滚策略&#xff0c;把一切都懂得特别混乱。很多时候初学者的难点根本不在于这个算法本身&#xff0c;而是它令人痛苦的百花齐放的定义。 有…...

python人工智能002:jupyter基本使用

小知识&#xff1a;将jupyter修改为中文&#xff0c;修改用户变量&#xff0c; 注意是用户变量&#xff0c;不是系统变量 新增用户变量 变量名&#xff1a;LANG 变量值&#xff1a;zh_CN.UTF8 然后重启jupyter 上一章的软件安装完成之后&#xff0c;就可以创建文件夹来学习写…...

Linux使用 firewalld管理防火墙命令

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

二叉树(三)

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

05--kubernetes组件与安装

前言&#xff1a;终于写到kubernetes&#xff08;k8s&#xff09;&#xff0c;容器编排工具不止k8s一个&#xff0c;它的优势在于搭建集群&#xff0c;也是传统运维和云计算运维的第一道门槛&#xff0c;这里会列出两种安装方式&#xff0c;详细步骤会在下文列出&#xff0c;文…...

EmguCV学习笔记 VB.Net和C# 下的OpenCv开发 C# 目录

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

探索TensorFlow:深度学习的未来

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

探索地理空间分析的新世界:Geopandas的魔力

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

如何为网站申请免费SSL证书?

一、准备阶段 确定证书类型&#xff1a; 对于大多数个人博客和小型企业网站&#xff0c;DV&#xff08;域名验证&#xff09;SSL证书已足够使用&#xff0c;因为它仅验证域名所有权&#xff0c;成本较低且验证快速。准备域名&#xff1a; 确保你拥有一个有效的域名&#xff0c…...

Java项目集成RocketMQ

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

如何将 Bamboo agent 能力迁移到极狐GitLab tag 上?

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

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...