2 C++中的引用

C++中的引用

上节说到,变量名实际上是一段连续存储空间的别名。很显然我们可以将其命名为其它名字,就像我们有乳名、小名一样。
C++引入了引用的概念。

  • 引用可以看作一个已定义变量的别名
  • 引用的语法 type& name = variate;
  • 普通引用在声明时必须用其它的变量进行初始化。用值进行初始化也不行(即int&a = 1; 会报错)
  • 引用作为函数参数时,声明时候不需要进行初始化
#include <stdio.h>
int main(int argc, char *argv[])
{int original = 1;int& new_name = original;//c语言无引用的概念,用gcc会编译报错。new_name = 2;printf("original = %d, new_name = %d\n", original, new_name);printf("&original = %p, &new_name =%p\n", &original, &new_name);return 0;
}

上面程序中,int& new_name = original; 用original别名叫new_name,当new_name赋值后,对于的存储空间的值也会变化,故original 的值和new_name值一样。相应的,他们的内存地址打印也相同,如下图:
在这里插入图片描述

引用的意义

  • 引用作为其它变量的别名而存在,因此在一些情况下可以代替指针
  • 引用相对于指针来说,具有更好的可读性和实用性
#include <stdio.h>//指针实现交换函数
void swap1(int* pa, int* pb)
{int c = *pa;*pa = *pb;*pb = c;
}//引用实现交换函数
void swap2(int& a, int& b)
{int c = a;a = b;b = c;
}int main(int argc, char *argv[])
{int var_1 = 8;int var_2 = 10;swap1(&var_1, &var_2);printf("after swap1, var_1 = %d, var_2 = %d\n", var_1, var_2);swap2(var_1, var_2);printf("after swap2, var_1 = %d, var_2 = %d\n", var_1, var_2);return 0;
}

上面程序中,引用实现的交换函数可读性更好。
swap1(&var_1, &var_2); 如果不看函数实现,像是交换两个变量的地址。
swap2(var_1, var_2); 从函数写法,像是交换两个变量。不像指针可读性差。
在这里插入图片描述

const 引用

  • 在C++中可以声明const 引用,语法 const Type& name = var;
  • const 引用让变量拥有只读属性,注意,只有定义的别名拥有只读属性,不会影响到正名。
#include <stdio.h>int main(int argc, char *argv[])
{int a = 8;const int& b = a;//变量a没有只读属性,当前只有变量b才有只读属性。//b = 10; //打开这里,报错 error: assignment of read-only reference ‘b’a = 20; //原来的变量还是可以赋值,不拥有只读属性printf("a = %d, b = %d\n", a, b);int *p = (int*)&b;*p = 10;	printf("a = %d, b = %d\n", a, b);	return 0;
}

在这里插入图片描述

  • 当使用常量对const引用进行初始化时(const int & a = 1; 我们知道直接使用常量赋值普通引用,编译器会报错, int& a = 1 会报错。),C++编译其会为常量分配空间,并将引用名作为这段空间的别名
  • 使用常量对const引用初始化后,将生成一个只读变量,而不是真正的常量
#include <stdio.h>int main(int argc, char *argv[])
{const int& a = 8; //这里编译器会为这个常量分配存储空间。去掉const 编译器会报错 cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’int *p = (int *)&a;*p = 10;//改变常量空间的地址内容printf("a = %d\n", a);	return 0;
}

在这里插入图片描述

引用的实现方式

引用有自己的存储空间吗?下面通过一个实例来验证。

#include <stdio.h>struct C
{int& a;//等价于 int* const a;int& b;//等价于 int* const b;
};int main(int argc, char *argv[])
{printf("sizeof(C) = %ld\n", sizeof(C));	return 0;
}

在这里插入图片描述
两个int型引用组成的结构体,打印的正好是2个int型变量的长度,从编译器行为来看,引用有自己的大小。

  • 引用在C++中的内部实现是一个常指针 type& name 等价于 type* const name。 type 指的是变量的类型,也可以指定义的新class类型, 例如:char& a 等价于 char* const a .
  • C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用占用的空间大小与指针占用空间大小相同。
  • 从使用者的角度,引用会让人误以为只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏。

下面再用一个例子来说明引用有自己的存储空间:

#include <stdio.h>struct T
{int& a;int& b;int& c;
};int main(int argc, char *argv[])
{int a = 1;int b = 2;int c = 3;T va = {a, b, c};printf("&a = %p\n", &a);	printf("&b = %p\n", &b);printf("&c = %p\n", &c);printf("&va = %p\n", &va);printf("sizeof(va) = %ld\n", sizeof(va));	return 0;
}

在这里插入图片描述
从打印结果来看,引用a,b,c都有自己的独立存储空间,va变量的空间为24字节,变量与变量内部的引用在内存上也是独立的。

当函数返回值为引用时

  • 返回栈变量
    1、不能成为其它引用的初始值
    2、不能作为左值使用
  • 返回静态变量或全局变量
    1、可以成为其他引用的初始值
    2、即可作为左值使用,也可作为右值使用
#include <stdio.h>int& f1()
{static int a = 8;return a;//返回静态局部变量a的内存空间,f1()函数作为该内存空间别名
}int& g1()
{int b = 6;return b;//返回局部变量b的内存空间,f1()函数作为该内存空间别名
}int main(int argc, char *argv[])
{int& c = f1();//返回静态局部变量a的存储空间别名给Cint& d = g1();//局部变量b内存空间别名,给到引用d. d代表局部变量b的内存空间。f1() = 10;//f1() 作为静态局部变量a的别名,然后给内存空间赋值10.相当于给静态局部变量赋值为10.printf("c = %d\n", c);	printf("d = %d\n", d); //打印被释放的空间别名值,出现段错误。printf("f1() = %d\n", f1());//去除掉上一行语句后,这里打印10.	return 0;
}

在这里插入图片描述
当引用返回的是局部变量时,局部变量所在的函数运行完成,会释放掉该局部变量,而我们去访问 被释放的引用存储空间时,会出现不可控的情况,这段内存有可能被系统回收给其他变量使用。
在g++上,printf(“d = %d\n”, d); 编译器发生了警告,当运行程序时,访问了被释放的存储空间别名,出现段错误。某些编译器和平台上,会打印出随机值。

回答上一节的问题,C++对三目运算符做了什么?

  • 当三目运算符可能返回值都是变量时,返回的值是变量的引用。
  • 当三目运算符可能返回中有常量时,返回的是值。
    int a = 6;
    int b = 8;
    ( a < b ? a : b) = 9;//语句正确,返回a 或者b的引用,可以作为右值使用。
    ( a < b ? a : b) = 9;//语句错误,返回值中有常量,返回的是值,不能作为右值使用。

小结

  • C++中的引用可以看作变量的别名来使用
  • C++中的常引用可以使得一个变量拥有只读属性
  • C++中的常引用可以用常量初始化而得到一个只读变量
  • C++中引用的本质是一个指针常量

思考

在C++中不允许定义引用数组 Type& array[10],为什么?
如何定义一个数组的应用?如何定义一个函数的引用?
数组引用和数组指针有什么区别?函数引用和函数指针又有什么区别?

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

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

相关文章

springboot和vue:二、springboot特点介绍+热部署热更新

springboot特点介绍 能够使用内嵌的Tomcat、Jetty服务器&#xff0c;不需要部署war文件。提供定制化的启动器Starters&#xff0c;简化Maven配置&#xff0c;开箱即用。纯Java配置&#xff0c;没有代码生成&#xff0c;也不需要XML配置。提供了生产级的服务监控方案&#xff0…

如何在 SOLIDWORKS中创建零件模板 硕迪科技

作为一款多功能且可大量定制的 3D CAD 软件&#xff0c;SOLIDWORKS模板可以通过自定义属性包含大量数据。可以通过为SOLIDWORKS零件、装配体和工程图创建模板来利用这些模板。 与其他一些CAD软件不同&#xff0c;SOLIDWORKS不限制您可以创建的模板数量 - 您可以根据需要创建任…

在项目中,关于前端实现数据可视化的技术选择

前言 在项目中&#xff0c;数据可视化以图表、报表类型为主。 需求背景 技术框架是Vue2.x版本&#xff0c;组件库是Ant Design of Vue能够支撑足够多的图表类型开发图表大小/位置能够随意变动图表样式需要支持丰富多样的用户配置强大、开放的图表语法支持复杂的数据可视化场景…

【深度学习实验】前馈神经网络(四):自定义逻辑回归模型:前向传播、反向传播算法

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 逻辑回归Logistic类 a. 构造函数__init__ b. __call__(self, x)方法 c. 前向传播forward d. 反向传播backward 2. 模型训练 3. 代码整合 一、实验介绍 实现逻…

Linux 目录结构介绍

对上面的说明: root 目录 &#xff1a; linux 超级权限 root 的主目录 home 目录 &#xff1a; 系统默认的用户主目录&#xff0c;如果添加用户是不指定用户的主目录&#xff0c;默认在/home 下创建与用户同名的文件夹 bin 目录 &#xff1a; 存放系统所需要的重要命令&am…

uniapp Echart X轴Y轴文字被遮挡怎么办,或未能铺满整个容器

有时候布局太小&#xff0c;使用echarts&#xff0c;x轴y轴文字容易被遮挡&#xff0c;怎么解决这个问题呢&#xff0c;或者是未能铺满整个容器。 方法1&#xff1a; 直接设置 containLabel 字段 options: { grid: { containLabel: true, },} 方法2: 间接设置&#xff0c;但是…

【新版】系统架构设计师 - 案例分析 - 信息安全

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 信息安全安全架构安全模型分类BLP模型Biba模型Chinese Wall模型 信息安全整体架构设计WPDRRC模型各模型安全防范功能 网络安全体系架构设计开放系统互联安全体系结构安全服务与安全机制…

mysql workbench常用操作

1、No database selected Select the default DB to be used by double-clicking its name in the SCHEMAS list in the sidebar 方法一&#xff1a;双击你要使用的库 方法二&#xff1a;USE 数据库名 2、复制表名&#xff0c;字段名 3、保存链接

vue3+ts 实现移动端分页

current 开始页码 pageSize 结束页码 const sizeref<number>(10) //一页显示十条 const eachCurrentPageref<number>(1) //默认是第一页interface ITdata {current: number,pageSize: number,// xxxx 其他参数... } const selectApplyList ref<…

联想电脑打开exe提示要在Microsoft Store中搜索应用

问题&#xff1a; 你需要为此任务安装应用。 是否要在Microsoft Store中搜索一个&#xff1f; 如图&#xff1a; 出现此情况&#xff0c;仅需要做如下操作&#xff0c;在要打开的exe文件上右键&#xff0c;属性&#xff1a; 如图箭头所示&#xff0c;点击“解除锁定”出现对钩&…

<十二>objectARX开发:Arx注册命令类型的含义以及颜色索引对应RGB值

1、注册命令类型 我们经常在acrxEntryPoint.cpp中看到注册命令如下: 那么各个宏定义代表什么意思呢? 主标识:(常用的) ACRX_CMD_MODAL: 在别的命令执行的时候该命令不会在其中执行。ACRX_CMD_TRANSPARENT: 命令可以再其它命令中执行,但在该标志下ads_sssetfirst()不能使…

LeetCode 494.目标和 (动态规划 + 性能优化)二维数组 压缩成 一维数组

494. 目标和 - 力扣&#xff08;LeetCode&#xff09; 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2…

用Redis做数据排名

1.背景 用Redis做数据缓存用的比较多&#xff0c;大家都能熟练使用String和Hash结构去存储数据&#xff0c;今天讲下如何使用ZSet来做数据排名。 假设场景是需要按天存储全国城市的得分数据&#xff0c;可以查询前十名的城市排名。 这个case可以使用传统关系型数据库做…

如何修复wmvcore.dll缺失问题,wmvcore.dll下载修复方法分享

近年来&#xff0c;电脑使用的普及率越来越高&#xff0c;人们在日常生活中离不开电脑。然而&#xff0c;有时候我们可能会遇到一些问题&#xff0c;其中之一就是wmvcore.dll缺失的问题。wmvcore.dll是Windows平台上用于支持Windows Media Player的动态链接库文件&#xff0c;如…

SD-MTSP:萤火虫算法(FA)求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、萤火虫算法&#xff08;FA&#xff09;简介 萤火虫算法(Firefly Algorithm&#xff0c;FA)是Yang等人于2009年提出的一种仿生优化算法。 参考文献&#xff1a;田梦楚, 薄煜明, 陈志敏, et al. 萤火虫算法智能优化粒子滤波[J]. 自动化学报, 2016, 42(001):89-97. 二、单仓…

数量关系(刘文超)

解题技巧 代入排除法 数字特性法 整除特性 比例倍数特性&#xff08;找比例&#xff0c;比例不明显时找等式&#xff09; 看不懂式子时&#xff0c;把所有的信息像表格一样列出来 看不懂式子时&#xff0c;把所有的信息像表格一样列出来

【机器学习】期望最大算法(EM算法)解析:Expectation Maximization Algorithm

【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm 文章目录 【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm1. 介绍2. EM算法数学描述3. EM算法流程4. 两个问…

性能测试 —— Tomcat监控与调优:Jconsole监控

JConsole的图形用户界面是一个符合Java管理扩展(JMX)规范的监测工具&#xff0c;JConsole使用Java虚拟机(Java VM)&#xff0c;提供在Java平台上运行的应用程序的性能和资源消耗的信息。在Java平台&#xff0c;标准版(Java SE平台)6&#xff0c;JConsole的已经更新到目前的外观…

Linux查看哪些进程占用的系统 buffer/cache 较高 (hcache,lsof)命令

1、什么是buffer/cache &#xff1f; buffer/cache 其实是作为服务器系统的文件数据缓存使用的&#xff0c;尤其是针对进程对文件存在 read/write 操作的时候&#xff0c;所以当你的服务进程在对文件进行读写的时候&#xff0c;Linux内核为了提高服务的读写速度&#xff0c;则将…

linux 约束

linux 约束 1、约束的概念1.1什么是约束1.2约束的优劣势 2、约束的作用3、约束的分类4、约束的应用场景5、约束的管理5.1创建5.2查看5.3插入5.4删除 6、总结 1、约束的概念 1.1什么是约束 在关系型数据库中&#xff0c;约束是用于限制表中数据规则的一种机制。它可以确保表中…