学习C++第三天——对引用的深入了解

引用

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


一个变量可以有多个引用:

int main() {//一个变量可以有多个引用int a = 10;int& b = a;int& c = a;int& d = a;return 0;
}

引用相当于给这个变量取别名,在西游记中孙悟空是孙悟空,齐天大圣也是孙悟空,弼马温也是孙悟空,孙行者也是孙悟空,斗战胜佛也是孙悟空,这些别名都是在指同一个猴子。

C++中的引用就相当于在给引用实体取别名


引用在定义的时候必须初始化:

对引用不初始化是会报错的

注意:引用类型必须和引用实体是同种类型的


引用一旦引用实体,就不能再引用其他实体:

int main() {int a = 10;int& b = a;int c = 20;b = c;cout << "a=" << a<<endl;cout << "b=" << b << endl;cout << "c=" << c << endl;return 0;
}
//输出结果a=20,b=20,c=20

b是a的别名,将c赋值给b,就相当于给a赋值,所以a,b,c的值都是20

所以引用一旦引用实体后就不能引用其他实体,否知就是将其他实体的内容拷贝到引用里面


引用做参数:

交换两个数

void swap(int& x, int& y) {int tmp = x;x = y;y = tmp;
}

在C语言中交换两个参数需要用到指针,比较麻烦,这里使用引用就比较方便

当引用做参数时,实参传过来,相当于x,y就是实参的别名,对引用进行修改也就是对实参进行修改

私货:

typedef struct ListNode {int val;struct nextNode* next;
}*PNode;void ListPushBack(PNode& phead, int x);

定义一个链表的节点,重定义节点指针类型为PNode,用PNode类型做引用的类型,所以改变phead就可以改变其里面的内容。

传值和传引用比较效率:

#include<iostream>
using namespace std;struct A {int arr[10000];};//定义一个字节数比较大的结构体void mothed1(A a) {};//传值的方法
void mothed2(A& a) {};//传引用的方法void test() {A a;//创建一个结构体size_t begin1 = clock();//记录传值方法开始的时间for (size_t i = 0; i < 10000; i++)//进行10000次传值{mothed1(a);}size_t end1 = clock();//记录传值结束的时间size_t begin2 = clock();//记录传引用开始的时间for (size_t i = 0; i < 10000; i++)//进行10000次传引用{mothed2(a);}size_t end2 = clock();//记录传引用结束的时间cout << end1 - begin1 << endl;//计算传值所花费的时间cout << end2 - begin2 << endl;//计算传引用所花费的时间
}int main() {test();//调用测试函数
}//结果为6,0

显然传引用的效率高于传值


引用做返回值:

传值返回:

 当返回值不是引用时,编译器都会生成临时变量

不管n时是否是static修饰的还是其他别的类型,只要是传值返回都要生成临时变量

传引用返回:

减少拷贝,提高效率,不会生成临时变量

struct A { int arr[10000]; };//定义一个结构体
A a;//创建一个结构体
A mothed1() { return a; };//实现一个传值返回函数
A& mothed2() { return a; };//实现一个传引用返回函数void test() {size_t begin1 = clock();//获取开始时间for (size_t i = 0; i < 10000; i++)//调用10000传值返回函数{mothed1();}size_t end1 = clock();//获取结束时间size_t begin2 = clock();//获取开始时间for (size_t i = 0; i < 10000; i++)//调用10000次传引用返回函数{mothed2();}size_t end2 = clock();//获取结束时间cout << end1 - begin1 << endl;//计算传值返回所用的时间cout << end2 - begin2 << endl;//计算传引用返回所用的时间
}int main() {test();
}
//输出结果为18,0

传值返回和传引用返回有很大差异,传引用返回的效率远高于传值返回

传引用返回的问题:

int& fun() {int n = 10;n++;return n;
}int main() {int ret=fun();cout<< ret;return 0;
}

当引用作为返回值时,没有临时变量,提高了效率。

当引用返回值用整形接收时,是将引用的内容拷贝到ret里面

当fun函数结束时,fun的函数栈帧会被销毁,也就是失去了访问权限

当ret指向的栈帧没有被清理时,结果不变

当ret指向的栈帧被清理后,结果为随机值

ret指向的空间没有保障

当传引用返回用引用接收:

int& fun() {int n = 10;n++;return n;
}int main() {int &ret=fun();cout<< ret<<endl;printf("<<<<<<<<<<<<<\n");rand();cout << ret;return 0;
}

当返回值用引用接收时,ret指向引用的那块空间,在不被清理的时候,ret的值侥幸正确,当被清理时,就会ret的值就会变成随机值,就算没被清理,当调用其他函数时,栈帧会被覆盖,那就毫无疑问的变成随机值了

返回引用的实体是被static修饰的:

int& fun() {static int n = 10;n++;return n;
}int main() {int &ret=fun();cout<< ret<<endl;printf("<<<<<<<<<<<<<\n");rand();cout << ret;return 0;
}

这时候使用引用返回是安全的

因为这时候的n是在静态区,fun结束,函数栈帧销毁对静态区的n没有影响

对引用的扩充使用:

typedef struct SeqList
{int a[10];size_t size;
}SqList;//定义一个简易的静态顺序表int SLGet(SeqList* ps, int pos) {//获取对应下标的值assert(pos >= 0 && pos < 10);return ps->a[pos];
}void Modify(SeqList* ps, int pos, int val) {//修改对应下标的值assert(pos >= 0 && pos < 10);ps->a[pos] = val;
}int main() {SeqList s;Modify(&s, 0, 1);cout << SLGet(&s, 0)<<endl;int ret = SLGet(&s, 0);Modify(&s, 0, ret + 5);cout << SLGet(&s, 0) << endl;return 0;
}

这样用c语言的指针写比较麻烦


#include<assert.h>typedef struct SeqList
{int a[10];size_t size;
}*SeqList;int& SLAt(SeqList& ps, int pos) {assert(pos >= 0 && pos < 10);return ps->a[pos];
}int main() {SeqList s;SLAt(s, 0) = 10;cout << SLAt(s, 0) << endl;SLAt(s, 0)++;cout << SLAt(s, 0) << endl;SLAt(s, 0) -= 3;cout << SLAt(s, 0) << endl;
}

引用做返回值有获取和修改返回值的功能,就可以实现指针的功能

#include<iostream>
#include<assert.h>
using namespace std;struct  SeqList
{int a[100];size_t size;int& at(int pos) {assert(pos >= 0 && pos < 100);return a[pos];}int& operator[](int pos) {assert(pos >= 0 && pos < 100);return a[pos];}};int main() {SeqList s;s.at(0) = 10;s.at(0)++;cout << s.at(0)<<endl;s[0] = 20;s[0]++;cout << s[0] << endl;return 0;
}

常引用:

1.权限不能扩大

int main() {//权限不能扩大const int a = 10;//int& b = a;const int& c = a;
}

a是const修饰变量,不能被修改,所以他的别名也必须被const修饰,保证权限不被扩大

2.const修饰的变量可以赋值

int main() {const int a = 10;int b = a;
}

const修饰的a相当于常量,不能被修改,但是可以赋值,相当于将a的内容拷贝到b里面

3.引用过程中权限可以缩小和偏移

int main() {int a = 10;int& b = a;//权限平移const int& c = a;//权限缩小b++;//c++;
}

上述权限平移可以执行原来的修改,但是权限缩小就不能修改了

int& fun1() {static int x = 10;return x;
}int main() {int& ret = fun1();//权限的平移const int& ret1 = fun1();//权限的缩小return 0;
}

ret和ret1均为x的别名

4.给常量取别名

int main() {const int& a = 10;
}

a是不能被修改的

5.隐式类型转化

 

 

6.临时变量具有常属性

所以ret需要const修饰

引用和指针的不同点:

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

2. 引用在定义时必须初始化,指针没有要求

3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体

4. 没有NULL引用,但有NULL指针

5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)

6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

7. 有多级指针,但是没有多级引用

8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

9. 引用比指针使用起来相对更安全

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

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

相关文章

OpenAI 收购桌面实时协作公司 Multi;iOS 18 开放 iPhone 镜像测试丨RTE 开发者日报 Vol.231

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

c++ 设计模式 的课本范例(上)

( 0 ) 这里补充面向对象设计的几个原则&#xff1a; 开闭原则OCP &#xff1a; 面向增补开放&#xff0c;面向代码修改关闭。其实反映到代码设计上就是类的继承&#xff0c;通过继承与多态&#xff0c;可以不修改原代码&#xff0c;又增加新的类似的功能。 依赖倒置原则 Depend…

如何从iPhone恢复错误删除的照片

嘿&#xff0c;iPhone 用户&#xff01;作为一名苹果专业人士&#xff0c;我见过相当多的“哎呀&#xff0c;我删除了它&#xff01;”的时刻。今天&#xff0c;我在这里指导您完成从iPhone中恢复那些珍贵的&#xff0c;错误删除的照片的迷宫。坐下来&#xff0c;拿起你的设备&…

分压电路 ADC计算电压 【老板再也不能开除我了 】

经典分压电路 一个电压过来 adc这里的电压等于&#xff1a; 如是12位adc 那么他最大值就是4095 如参考电压是5v 则&#xff1a;5v/4095 实际电压V*(R2/(R1R2)&#xff09;/adc值 转化&#xff1a;实际电压V 5v*(adc值/4095)/(R2/(R1R2)) &#xff1a;老板再也不能 因为不会…

PointCloudLib-滤波模块(Filtering)-直通滤波

使用直通过滤器过滤点云 在本教程中,我们将学习如何沿着 指定维度 – 即,切断位于 或 在给定用户范围之外。 代码 首先,创建一个文件,比方说,在你最喜欢的 编辑器,并将以下内容放入其中:passthrough.cpp #include <iostream> #include <pcl/point_types.h&g…

推荐系统-FM模型

参考&#xff1a;推荐系统&#xff08;三&#xff09;Factorization Machines&#xff08;FM&#xff09;_svmmf-CSDN博客 一句话概括下FM&#xff1a;隐式向量特征交叉----类似embedding的思想 LR 如果利用LR做特征的二阶交叉&#xff0c;有&#xff1a; 但这个公式存在显著…

Open3D 点云的ISS关键点提取

目录 一、概述 1.1原理 1.2应用场景 1.3算法实现步骤 二、代码实现 2.1 完整代码 2.2关键函数 2.3关键点可视化 三、实现效果 3.1原始点云 3.2提取后点云 一、概述 1.1原理 ISS&#xff08;Intrinsic Shape Signatures&#xff09;关键点提取是一种常用于三维点云的…

【LLM-多模态】高效多模态大型语言模型综述

一、结论写在前面 模型规模的庞大及训练和推理成本的高昂&#xff0c;限制了MLLMs在学术界和工业界的广泛应用。因此&#xff0c;研究高效轻量级的MLLMs具有巨大潜力&#xff0c;特别是在边缘计算场景中。 论文深入探讨了高效MLLM文献的领域&#xff0c;提供了一个全面的视角…

Win10可用的VC6.0绿色版及辅助插件assist_X

VC6.0&#xff0c;作为微软的经典开发工具&#xff0c;承载着无数开发者的青春与回忆。它曾是Windows平台上软件开发的重要基石&#xff0c;为开发者们提供了稳定且强大的编程环境&#xff0c;尤其是其MFC&#xff08;Microsoft Foundation Classes&#xff09;库&#xff0c;为…

SSM宠物领养系统-计算机毕业设计源码08465

目 录 摘要 1 绪论 1.1课题背景及意义 1.2研究现状 1.3ssm框架介绍 1.3论文结构与章节安排 2 宠物领养系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 …

uni-push(2.0)常见问题,Android平台

将常用的网址一定要收藏在标签栏中&#xff0c;方便后期找&#xff0c;不然后期会很生气。 草料二维码&#xff0c;这个在线工具可以将打包生成的apk文件生成二维码&#xff0c;供测试人员测试。生成的apk只有五次下载机会&#xff0c;可点击链接后的一键上传&#xff0c;这样…

数据资产管理的艺术之道:深入探索如何在数据价值的最大化、个人隐私的严密保护以及企业持续发展的战略需求之间找到微妙的平衡

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业最宝贵的资产之一。从市场营销到产品研发&#xff0c;从客户服务到运营管理&#xff0c;数据无处不在&#xff0c;为企业提供了前所未有的洞察力和竞争力。然而&#xff0c;随着数据量的激增和数据类型的多样化&#xff0…

【Linux网络(一)初识计算机网络】

一、网络发展 1.发展背景 2.发展类型 二、网络协议 1.认识协议 2.协议分层 3.OSI七层模型 4.TCP/IP协议 三、网络传输 1.协议报头 2.局域网内的两台主机通信 3.跨网络的两台主机通信 四、网络地址 1.IP地址 2.MAC地址 一、网络发展 1.发展背景 计算机网络的发展…

七天速通javaSE:第三天 程序控制结构:顺序、选择、循环

文章目录 前言一、Scanner类1. hasNext()和hasNextLine()2.next()和nextLine()3. Scanner的其他用法 二、顺序结构三、选择结构1. if单选择结构2. if-else双选择结构3. if-else if多选择结构4. switch选择结构 四、循环结构1. while循环2.do while循环3. for循环&#xff08;常…

表单(forms)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在app1文件夹下创建一个forms.py文件&#xff0c;添加如下类代码&#xff1a; from django import forms class PersonForm(forms.Form): first_na…

C语言·动态内存管理

1. 为什么要有动态内存管理&#xff1f; 例1&#xff1a; //固定的向内存申请4个字节 int a 10;//申请连续的一块空间 int arr[10]; 这些数据一旦声明定义之后就会在内存中有一块空间&#xff0c;这些空间都是固定的&#xff0c;为了让内存使用更加灵活&#xff0c;这时我们…

【复旦邱锡鹏教授《神经网络与深度学习公开课》笔记】卷积

卷积经常用在信号处理中&#xff0c;用于计算信号的延迟累积。假设一个信号发射器每个时刻 t t t产生一个信号 x t x_t xt​&#xff0c;其信息的衰减率为 w k w_k wk​&#xff0c;即在 k − 1 k-1 k−1个时间步长后&#xff0c;信息为原来的 w k w_k wk​倍&#xff0c;时刻 …

SpringBoot开启事务日志

一般框架开启日志的方式&#xff1a; 开启某个包下的日志就写该包路径&#xff0c;开启某个类下的日志就写该类路径。

【数据结构】栈的定义与实现(附完整运行代码)

目录 一、栈的定义 二、顺序栈 链栈比较 三、栈的实现&#xff08;顺序栈&#xff09; 3.1 ❥ 定义栈结构 3.2 ❥ 初始化 3.3 ❥ 销毁 3.4 ❥ 插入&#xff08;入栈&#xff09; 3.5 ❥ 删除 &#xff08;出栈&#xff09; 3.6 ❥ 获取栈顶元素 3.7 ❥ 判空 3.8 ❥…

【Android】创建一个可以在屏幕上拖动的悬浮窗

项目需求 在界面上创建一个悬浮窗&#xff0c;可以自由的移动这个悬浮窗 需求解决 1.添加权限 <uses-permission android:name"android.permission.SYSTEM_ALERT_WINDOW"/>2.请求权限 从 Android 6.0 (API 23) 开始&#xff0c;应用需要动态请求显示悬浮窗…