【C++初阶(三)】引用详解(对比指针)

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++初阶之路⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习排序知识
  🔝🔝


在这里插入图片描述

引用

  • 1. 前言
  • 2. 引用的概念
  • 3. 引用的特性
  • 4. 常引用
  • 5. 使用场景
    • 5.1 引用做函数参数
    • 5.2 引用做函数返回值
  • 6. 注意事项
  • 7. 传值和传引用效率分析
  • 8. 引用和指针的联系
  • 9. 引用和指针的区别
  • 10. 总结以及拓展

1. 前言

C语言中有一利器: 指针
而C++中增加了另一利器: 引用
这两个板块的存在
极大了提升了C/C++的可用性!

在这里插入图片描述

本篇文章将给大家详细讲解引用
并且分析引用和指针的联系和区别
最后给大家拓展C++中的空指针


2. 引用的概念

概念:

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

比如说孙悟空又叫
孙行者,齐天大圣,斗战胜佛

李逵又叫黑旋风,铁牛

类型& 引用变量名(对象名) = 引用实体
引用符号:&

举个例子来说明:

	int a = 10;int& ra = a;//<====定义引用类型printf("%p\n", &a);//打印地址printf("%p\n", &ra);

打印出来的地址相同
在这里插入图片描述


并且引用值改变,原先的值也会改变!

int a = 10;int& ra = a;cout << ra <<' '<< a;cout << endl;ra = 20;cout << ra << ' ' << a;

a的值会从10被修改成20
在这里插入图片描述


3. 引用的特性

引用特性:

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 一旦引用一个实体,就不能引用其他实体

特性讲解:

int a = 10;
int& ra; // 没初始化,会报错
int& ra = a;
int& rra = a;
int& rrra = a;
//这三个都是a的引用,只要其中一个
//发生改变,其他三个也会改变
printf("%p %p %p %p\n", &a, &ra, &rra, &rrra);  
int a = 10;
int& ra = a;
int b = 20;
ra = b; //这条语句的意思是将b的值赋值给a//而不是ra从a的引用变成b的引用
cout << ra << ' ' << a << ' ' << b;
cout << endl;
printf("a的地址:%p ra的地址:%p b的地址:%p", &a, &ra, &b);

可以看见ra的地址和a是一样的
一旦引用初始化后就不能改变引用对象

在这里插入图片描述


4. 常引用

顾名思义就是引用常量
但是常量具有不可修改性
所以引用一个常量时要加上const

const int a = 10;
//int& ra = a;   // 该语句编译时会出错,a为常量
const int& ra = a;
// int& b = 10; // 该语句编译时会出错,b为常量const int& b = 10;
double d = 12.34;
//const int& rd = d; // 该语句编译时会出错,类型不同
const double& rd = d;

并且引用的类型要对上

int类型的引用对应int&
double类型的引用对应double&


5. 使用场景

5.1 引用做函数参数

引用做函数参数

之前在写C程序的交换函数时
因为形参是实参的一份拷贝
想要改变实参就要传地址
而现在有了引用就不用传地址了!

void Swap(int& left, int& right)//交换函数
{int temp = left;left = right;right = temp;
}int a = 10;
int b = 20;
Swap(a,b);//因为形参为引用,所以这传的是a,b的引用

注: 引用传参时,不用加符号&
& 符号放在类型后面时是引用
其他地方& 符号都是取地址!


5.2 引用做函数返回值

引用做返回值

引用做返回值时
可在函数外面修改函数里面的内容
前提是引用的变量出了函数不会销毁

static int n = 0;
int& Count()
{n++;n++;return n;
}int& tmp = Count();
tmp = 20;
cout << tmp << ' ' << n;

由于局部变量出了作用域会销毁
所以这里在函数中定义的是静态变量

并且修改tmp的值会改变n的值

在这里插入图片描述


6. 注意事项

下面这段代码不能用传引用返回:

int& Add(int a, int b)
{int c = a + b;return c;
}

因为函数调用完后C就被销毁了
而将C的引用返回后
会有类似于使用野指针的风险

总结:

如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。


7. 传值和传引用效率分析

  1. 作为函数返回值的比较
  • 传值返回分析

首先,传值返回并不是单纯的将
返回值直接传给外面的变量
而是会生成一个中间变量的拷贝
这个中间变量再将值拷贝给外面的变量

(注:在栈帧创建与销毁有详细介绍)

画图理解:

在这里插入图片描述
然而传引用返回没有这么复杂的过程

综上所述:

因此用值作为参数或者返回值类型
效率是非常低下的
尤其是当参数或者返回值类型非常大时
效率就更低


8. 引用和指针的联系

它们的联系:

  1. 语法层面上

引用在语法概念上就是一个别名
和实体共用一份空间

  1. 底层实现上

引用在底层实现上是有空间的
因为引用是按照指针的方式来实现的
也就是指针的底层汇编和引用一样

左边为引用,右边为指针:

在这里插入图片描述


9. 引用和指针的区别

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  1. 引用在定义时必须初始化,指针没有要求
  1. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  1. 没有NULL引用,但有NULL指针
  1. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
  1. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  1. 有多级指针,但是没有多级引用
  1. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  1. 引用比指针使用起来相对更安全

10. 总结以及拓展

总结:

总的来说,C++中更喜欢用引用
特别是在一些容器中,如:栈,队列
使用引用的效率会提高许多
在类和对象中引用也是重量级的存在
所以说引用十分的重要!

在这里插入图片描述

拓展:

C++中的空指针不用NULL
而是用nullptr来替代

(nullptr是关键字,使用时不用包头文件)

为了提高C++代码的可读性
在后续表示指针空值时
建议最好使用nullptr。


🔎 下期预告:内联函数和auto关键字 🔍

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

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

相关文章

Node.js知识梳理(二)——进阶

以下内容来自对《从前端到全栈》一书的学习记录~ 学习的时候用的是V16.20.0&#xff0c;18之后的语法差别还是有的~ 请求优化 我们在请求资源的时候&#xff0c;是需要做优化的&#xff0c;这里的优化涉及到了缓存。浏览器的缓存策略有两种&#xff1a; 强缓存协商缓存 关于…

Valve 签约开源 Linux 图形驱动开发者

导读据外媒 phoronix 报道&#xff0c;Valve 最近聘用了著名开源 Linux 图形驱动开发者 Alyssa Rosenzweig&#xff0c;以改进开源 Linux 图形驱动程序堆栈&#xff0c;增强 Linux 游戏生态系统。 Alyssa Rosenzweig 多年来在 Panfrost 开源、逆向工程 Arm Mali 图形驱动程序方…

Zabbix监控软件 Linux外多平台监控【Windows JAVA SNMP】

在之前的博客中&#xff0c;已经介绍了zabbix的安装&#xff0c;配置&#xff0c;以及如何用zabbix监控Linux服务器。这篇博客则介绍zabbix监控的其他几种方式&#xff08;Windows服务器 Java应用 SNMP&#xff09;。 -------------------- Zabbix 监控 Windows 系统 ---------…

[ABC218G] Game on Tree 2 树上游戏

[ABC218G] Game on Tree 2 树上游戏 文章目录 [ABC218G] Game on Tree 2 树上游戏题面翻译输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 题目大意分析水法code 正解code 题面翻译 给定一棵树&#xff0c;以及…

Vue 之 mixins 和 provide/inject

一、mixins 1、简介 ​ mixins 又称 混入&#xff0c;是指将一些可复用的代码&#xff08;JS、生命周期钩子函数等等&#xff09;抽离出来&#xff0c;定义成mixins模块&#xff0c;然后混入到多个组件中&#xff0c;从而实现组件间的逻辑代码共享&#xff0c;减少重复代码。…

Web安全——数据库mysql学习

数据库mysql基础 Web安全分享一、数据库的基本操作1、MYSQL登录与退出2、MYSQL数据库的一些解释3、MYSQL注释符有三种&#xff1a; 二、数据库的一些基本操作1、数据库的增删改查(sql语句) 三、table 表的操作1、查看表结构2、查看表的内容3、建立表4、约束条件5、修改表的操作…

macOS Sonoma 14 beta 3 (23A5286g) Boot ISO 原版可引导镜像下载

macOS Sonoma 14 beta 3 (23A5286g) Boot ISO 原版可引导镜像&#xff0c;7 月 5 日&#xff08;北京时间今日凌晨&#xff09;已发布 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U…

GaussDB云数据库SQL应用系列—分区表管理

目录 前言 一、分区表基本原理 二、分区表主要优势 三、分区表常见场景 四、GaussDB分区表管理&#xff08;示例&#xff09; 示例一&#xff1a;创建范围分区表(RANGE) 示例二&#xff1a;创建哈希分区表&#xff08;HASH&#xff09; 示例三&#xff1a;创建列表分区…

vue3 实现多层级列表

文章目录 需求背景解决效果index.vue视频效果 需求背景 需要在统一个列表下&#xff0c;实现商品和规格得管理和联动 解决效果 index.vue <!--/*** author: liuk* date: 2023/7/7* describe: 商品列表 */--> <template><div class"container">&…

Java类加载深度剖析-大白话

Java类加载深度剖析 1.类加载的入口2.AppClassLoader、ExtClassLoader、BootstrapClassLoader的血脉渊源3.ExtClassLoader究竟是不是孙大圣4.为什么自定义类加载器的父类加载器是AppClassLoader呢&#xff1f;5.我们应该如何打破双亲委派机制呢&#xff1f;6.如何保证同class对…

Mac VSCode配置运行单个C++文件

题外话&#xff1a;VSCode一键整理代码快捷键&#xff1a;ShiftoptionF 方法一&#xff1a;命令行直接编译 g -o 想创建的可执行文件名 ./cpp文件名 ./可执行文件名 以test.cpp为例&#xff0c;我创建的可执行文件名为test&#xff0c;运行结果如下&#xff1a; 方法二&#…

【裸机开发】GPT 定时器(一) —— GPT的功能、寄存器解析

后续需要使用 GPT 计数器实现中断以及延时&#xff0c;这里我们需要先了解一下GPT的功能以及相关寄存器。 目录 一、GPT 定时器的功能 1、计数器 2、输入捕获 3、输出比较&#xff08;GPT的两种工作模式&#xff09; 二、寄存器解析 1、GPTx_CR 2、GPTx_PR 3、GPTx_SR …