C++内联函数与引用(超详细)

文章目录

  • 前言
  • 一、内联函数
    • 1.为什么会存在内联函数
    • 2.什么是内联函数
    • 3.内联函数注意事项
  • 二、引用
    • 1.什么是引用
    • 2.引用的特性
    • 3.常引用
    • 4.引用使用场景
    • 5.引用与指针
  • 总结


前言

一、内联函数

1.为什么会存在内联函数

🧐🧐首先我们介绍内联函数之前,首先看一下我们之前学过的#define 定义的宏

写一个宏函数,实现两个函数的相加

#include <iostream>
using namespace std;

#define ADD(x,y) ((x)+(y))
int main()
{
	int a = 10;
	int b = 20;
	cout << ADD(a,b) << endl;
	return 0;
}

想想我们当初学习宏函数的的优点和缺点
⚾⚾优点:这些函数我们也可以用函数来实现,但是函数调用需要开辟栈帧,浪费空间,
而宏就完美解决了这个问题,它会在调用它的地方展开。进行完全替换。
⚾⚾缺点:不能调试,使用起来复杂,没有安全类型的检查,代码可读性差

那我们可不可以实现一个专门的库函数,既包含宏的有点又避免了函数调用的缺点呢??
这时内联函数就出现了!!!

2.什么是内联函数

✨ ✨概念:用inline修饰的函数就是内联函数,编译时C++编译器会在调用的地方展开,没有函数调用建立栈帧的开销,提高程序运行效率。

int add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = add(a, b);
	cout << ret<< endl;
	return 0;
}

我们转到反汇编看一下这段代码

在这里插入图片描述

在正常情况下,没有加内联函数确实进行了函数调用建立栈帧。

我们加上内联函数再来看一下

在这里插入图片描述
我们发现怎末跟上面代码一样,都调用了add函数,建立了栈帧。这厮怎末回事???

这是因为在Debug模式下,方便调试,编译器默认不进行优化,也就是不进行展开,依然使用一般的函数调用。
我们对vs设置一下环境
在这里插入图片描述
可以看到,优化之后inline修饰过的函数会直接展开。

也就是说,在Debug模式下你写代码、调试代码时,inline 相当于普通函数,可以进行调试;在release模式下,又可直接进行原地展开,提高效率(这里指的是避免了调用函数、创建栈帧等方面的资源消耗)

在这里插入图片描述

3.内联函数注意事项

🎇🎇内联函数是一种以空间换时间的方法,如果编译器将函数当成内联函数处理,在编译阶段,会当成函数体替换来调用。
缺陷:函数体目标变大
优势:少了调用开销,提高程序运行效率

🎇🎇内联函数对于编译器来说,只是一个建议,不同编译器关于inline实现机制可能不同,一般建议函数规模较小的,不是递归实现,调用频繁的采用内联函数修饰,否则编译器会忽略inline的特性

🎇🎇inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

main.cpp

#include "add.h"
int main()
{
	int ret = add(10, 20);
	cout << ret<< endl;
	return 0;
}

add.cpp

#include "add.h"
inline int add(int x, int y)
{
	return x + y;
}

add.h

#include <iostream>
using namespace std;

inline int add(int x, int y);

严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2019 无法解析的外部符号 “int __cdecl add(int,int)” (?add@@YAHHH@Z),函数 main 中引用了该符号 12_29 D:\study C\c嘎嘎\12_29\12_29\main.obj 1

我们一般建议把内联函数放在一个文件夹中进行处理

#include <iostream>
using namespace std;
inline int add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = add(10, 20);
	cout << ret<< endl;
	return 0;
}

二、引用

1.什么是引用

其实引用就是给变量取别名,这个别名和这个变量共用同一块空间。

使用:类型名 &别名=变量名; 对别名的改变同样也改变变量名的值

在这里插入图片描述

引用只能用于同类型变量才可以

在这里插入图片描述

2.引用的特性

引用时必须初始化

在这里插入图片描述

可以给一个变量取多个别名,也可以给别名起别名

在这里插入图片描述

引用一旦引用了一个实体,就不可以在引用其他实体

在这里插入图片描述

3.常引用

我们对引用加上const修饰后会发生什么呢???

权限不可以扩大,本来是const int 类型,现在变成了int类型

在这里插入图片描述
那我们如何进行修改呢??
只要在引用前边加上const就可以

这其实就是权限的平移,本来是一个const int 类型,现在变成了const int 。两个权限一致

在这里插入图片描述

深度理解临时变量

我们看一下这段代码
在这里插入图片描述

我们发现他出错了,但是为什么会出错呢??
有点人感觉这是类型不匹配导致的!!但其实并不是这样,他还有更深层次的理解

隐式类型转化,强转,截断都会发生产生临时变量,这个临时变量具有常性(不可被修改)

举个例子::
int a=10;double b=a;
这段代码肯定不会报错,会正常运行,但是他为什么可以实现呢???
本质是编译器把a那个变量进行了拷贝,产生了临时变量,通过这个临时变量取进行类型转化✨✨✨✨

权限既然不能放大,那我们可不可以缩小呢??
这个其实是可以的,我们来具体看一下

在这里插入图片描述

4.引用使用场景

作为函数参数,进行传参,避免指针的使用错误

我们来回忆一下之前c语言通过一个函数对两个变量进行交换,我们的形参必须用指针才可以实现,是不是很麻烦,那这时我们就可以用引用来实现了!!!

在这里插入图片描述
在这种场景下我们用引用就会非常方便

作为函数参数,进行传参,避免拷贝,提高程序运行效率

想想我们当时为什么会用指针来进行传参,比如我们传结构体传参,会生成一份原大小的拷贝,对资源浪费非常大。指针传参仅仅会拷贝4/8个字节,减少了空间的浪费。那我们也可以用引用来进行传参,南无连这个4/8个字节的拷贝也不需要了。
在这里插入图片描述

作为返回值,进行传参,避免拷贝,提高程序运行效率

我们知道调用函数,我们并不是返回的那个对象,而是那个对象那个的拷贝,我们也可以通过进行引用返回避免拷贝

在这里插入图片描述

作为返回值,我们还可以对返回值进行修改,做返回值如果出了作用于还在,可以用传引用返回,如果出了作用域就不在了(销毁了),那就不能用传引用返回,只能用传值返回

5.引用与指针

在语法概念上,我们知道,引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

在这里插入图片描述

但是在底层上,我们会发现,引用也是用指针实现的

我们转到反汇编观察一下
在这里插入图片描述

🌟指针存储一个变量地址,而引用是一个变量的别名
🌟引用必须初始化,指针没有要求
🌟引用一旦引用了一个实体,就不可以再引用其他实体。地址可以在任何时候指向一个
同类型的实体
🌟只有空指针,没有空引用
🌟只有多级指针,没有多级引用
🌟引用+1是指向的变量大小进行加一,指针+1是跳过一个指向类型的大小的地址
🌟引用大小为引用实体的大小,而指针的大小是4/8字节
🌟访问方式不同,指针需要解引用访问,引用编译器自己处理
🌟引用使用起来比指针相对安全

总结

以上就是今天要讲的内容,本文仅仅详细介绍了C++内联函数与引用,希望对大家的学习有所帮助,仅供参考 如有错误请大佬指点我会尽快去改正 欢迎大家来评论~~ 😘 😘 😘 😘

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NVMe over Fabrics:概念、应用和实现

对于大部分人来说&#xff0c;NVMe over Fabrics&#xff08;简称NVMf&#xff09;还是个新东西&#xff0c;因为其第一个正式版本的协议在今年6月份才发布。但是这并不影响人们对NVMf的关注&#xff0c;因为这项依托于NVMe的技术很可能继续改变存储市场格局。 NVMf的贡献在于…

USB -- STM32F103复合设备(HID+MassStorage)传输讲解(十)

目录 链接快速定位 前沿 1 描述符讲解 1.1 设备描述符 1.2 配置描述符 1.3 接口描述符 1.4 功能描述符 1.5 端点描述符 1.6 字符串描述符 1.7 报告描述符 2 运行演示 链接快速定位 USB -- 初识USB协议&#xff08;一&#xff09; 源码下载请参考链接&#xff1a;…

vivado CDC约束-“设置总线倾斜”对话框

“设置总线倾斜”对话框 在AMD Vivado™ IDE中&#xff0c;可以通过多种方式设置总线偏斜约束&#xff1a; •通过时间约束编辑器。选择窗口 → 时间限制 → 断言 → 设置总线倾斜。从“时序约束编辑器”中&#xff0c;可以添加、删除或修改总线扭曲约束。 注意&#…

【VSCode】关闭双击shift出现搜索

原因 有时候总是手滑按两下shift&#xff0c;每次都会弹出如下图的搜索框&#xff0c;导致很不方便 解决办法 找到该文件 C:\Users\admin\.vscode\extensions\k--kato.intellij-idea-keybindings-1.5.12\package.json&#xff08;admin是自己的用户名&#xff09; 然后关键字…

【MySQL视图特性】

目录&#xff1a; 前言视图基本使用创建视图查看视图内容修改内容测试删除视图 视图规则和限制 前言 剑指offer&#xff1a;一年又12天 视图 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图也是带有名称的列和行内容&#xff0c;对视图内容的…

Java集合/泛型篇----第二篇

系列文章目录 文章目录 系列文章目录前言一、说说List,Set,Map三者的区别二、Array与ArrayList有什么不一样?三、Map有什么特点四、集合类存放于 Java.util 包中, 主要有几 种接口前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。…

系列四、Eureka自我保护

一、Eureka自我保护 1.1、故障现象 保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式&#xff0c;Eureka Server将会尝试保护其服务注册表中的信息&#xff0c;不再删除服务注册表中的数据&#xff0c;也就是不会注销任何微服务。如…

学生信息管理系统winform+sqlserver

学生信息管理系统winformsqlserver Winform作为一个强大的桌面应用程序开发工具&#xff0c;具有丰富的图形化界面编程组件&#xff0c;可以快速构建出用户友好的界面。使用这个工具&#xff0c;我能够轻松设计出适合学生信息管理系统的各类窗体&#xff0c;比如学生信息录入窗…

------- 计算机网络基础

1.1概述 是什么? 答出独立计算机通信线路连接实现资源共享 计算机网络组成 从组成部分看: 硬件软件协议 从工作方式看: 边缘部分和核心部分 从功能组成看: 通信子网和资源子网 计算机网络性能指标 速率是指数据传输的物理速度&#xff0c;吞吐量是指实际的数据传输…

Redis:原理速成+项目实战——Redis的Java客户端

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis常见命令&#xff08;数据结构、常见命令总结&#xff09; &#x1f4da;订阅专栏&…

Qt Creator可视化交互界面exe快速入门5

上一期介绍了加法计算器,本期介绍QObject定时器。 首先一样先建个工程,比如我这项目名为QObject 本期的任务就是制作图片在界面上显示,然后每秒定时切换,点击另一个暂停按钮,可以定格当前图片,即取消定时切换功能。 显示图片的我们可以使用显示里面的label 这个用于显示…

STM32+Codesys工业软件PLC解决方案

工业控制系统在现代制造和自动化领域扮演着关键角色, 基于IEC 61131-3 标准的控制器编程开发软件平台CODESYS&#xff0c;适用于多种行业的控制系统的开发,使用户方便快捷地对自动化工程进行编程和配置&#xff0c;完成项目开发、软件测试和应用调试。 本次STM32联合合作伙伴C…

设计模式(4)--对象行为(8)--状态

1. 意图 允许一个对象在其内部状态改变时改变它的行为。 2. 三种角色 上下文环境(Context)、抽象状态(State)、具体状态(Concrete State) 3. 优点 3.1 将与特定状态相关的行为局部化&#xff0c;并且将不同状态的行为分割开来。 3.2 使得状态转换显式化。 3.3 State对象可被共…

超详细YOLOv8姿态检测全程概述:环境、训练、验证与预测详解

目录 yolov8导航 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; 搭建环境说明 不同版本模型性能对比 不同版本对比 参数解释 模型解释 训练 训练示意代码 训练数据与.yaml配置方法 .yaml配置 数据集路径 标签数据说明 训练参数说明 训练过程示意及输出…

低代码开发中业务蓝图的重要性:业务需求与系统实现的桥梁

在低代码应用开发领域&#xff0c;业务蓝图是一个至关重要的工具&#xff0c;它提供了组织业务流程需求的详细信息。它类似于一份指导开发人员进行应用开发的路线图&#xff0c;确保与业务的战略目标和需求保持一致。 低代码方法学&#xff0c;顾名思义&#xff0c;即减少了传…

基于AM62x的ARM+FPGA+Codesys低成本软PLC解决方案

GPMC并口简介 GPMC(General Purpose Memory Controller)是TI处理器特有的通用存储器控制器接口&#xff0c;支持8/16bit数据位宽&#xff0c;支持128MB访问空间&#xff0c;最高时钟速率133MHz。GPMC是AM62x、AM64x、AM437x、AM335x、AM57x等处理器专用于与外部存储器设备的接口…

交叉验证的种类和原理(sklearn.model_selection import *)

交叉验证的种类和原理 所有的来自https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation-iterators并掺杂了自己的理解。 文章目录 前言一、基础知识1.1 交叉验证图形表示1.2 交叉验证主要类别 二、部分交叉验证函数&#xff08;每类一个&#xff0…

SQL注入【ByPass有点难的靶场实战】(九)

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 0、总体思路 先确认是否可以SQL注入&#xff0c;使用单…

Unity坦克大战开发全流程——开始场景——设置界面

开始场景——设置界面 step1&#xff1a;设置面板的背景图 照着这个来设置就行了 step2&#xff1a;写代码 关联的按钮控件 监听事件函数 注意&#xff1a;要在start函数中再写一行HideMe函数&#xff0c;以便该面板能在一开始就能隐藏自己。 再在BeginPanel脚本中调用该函数即…

ESP32入门六(读取引脚的模拟信号[2]:信号出现误差的原因)

在之前的章节中&#xff0c;我们测试了用ESP32来接收模拟电压信号&#xff0c;在测试中&#xff0c;读取到的数据与现实存在一定的误差&#xff0c;在这一篇中&#xff0c;我们尝试了解出现误差的原因和解决方法。 对于出现的误差&#xff0c;有多种软件和硬件方面的原因: 一、…