【C++入门到精通】C++入门 —— 引用、内联函数

news2024/11/26 12:18:01

目录

一、引用

1.引用的概念

2.引用的特性

3.常引用

4.引用的使用场景

        ⭕做参数

        ⭕做返回值

5.传值、传引用效率比较

值和引用的作为返回值类型的性能比较

6.引用和指针的区别

 引用和指针的不同点

 二、内联函数

1.内联函数的概念

2.内联函数的特性

3.宏与内联函数

宏的优缺点

🔴优点:

🔴缺点:

在C++中代替宏的方法


前言

         前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的命名空间的一些知识点以及关于C++的缺省参数、函数重载,也相信大家都掌握的不错,接下来博主将会带领大家继续学习有关C++的知识点——引用 和 内联函数。下面话不多说坐稳扶好咱们要开车了。

一、引用

1.引用的概念

        在C++中,引用是一种用于简化变量操作的概念。通过引用,可以创建一个已存在变量的别名,用于在程序中对原变量进行操作,简单来说引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。引用的使用方式是在变量声明时在其类型前加上&符号,例如:

int num = 10;
int& ref = num;// 引用声明和初始化

        在上面的例子中,ref 是对 num 的引用,它们指向同一个内存位置。因此,对 ref 的操作实际上是对 num 的操作,它们完全等价。

         类型& 引用变量名(对象名) = 引用实体;

void TestRef()
{
    int a = 10;
    int& ra = a;//<====定义引用类型

    printf("%p\n", &a);
    printf("%p\n", &ra);
}

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

2.引用的特性

1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
4.传递函数参数:通过引用传递函数参数,可以在函数内部修改原始变量的值,而无需进行拷贝。

3.常引用

void TestConstRef()
{
    const int a = 10;
    //int& ra = a; // 该语句编译时会出错,a为常量

    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;

    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

4.引用的使用场景

        ⭕做参数

void Swap(int& left, int& right)
{
    int temp = left;
    left = right;
    right = temp;
}

        ⭕做返回值

int& Count()
{
    static int n = 0;
    n++;
    // ...  代码块
    return n;
}

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

5.传值、传引用效率比较

        以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A{ int a[10000]; };

void TestFunc1(A a){}

void TestFunc2(A& a){}

void TestRefAndValue()
{
    A a;
    // 以值作为函数参数
    size_t begin1 = clock();
    for (size_t i = 0; i < 10000; ++i)
        TestFunc1(a);
    size_t end1 = clock();
    
    // 以引用作为函数参数
    size_t begin2 = clock();
    for (size_t i = 0; i < 10000; ++i)
        TestFunc2(a);
    size_t end2 = clock();

    // 分别计算两个函数运行结束后的时间
    cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
    cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

值和引用的作为返回值类型的性能比较

#include <time.h>
struct A{ int a[10000]; };

A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}

void TestReturnByRefOrValue()
{
    // 以值作为函数的返回值类型
    size_t begin1 = clock();
    for (size_t i = 0; i < 100000; ++i)
        TestFunc1();
    size_t end1 = clock();

    // 以引用作为函数的返回值类型
    size_t begin2 = clock();
    for (size_t i = 0; i < 100000; ++i)
        TestFunc2();
    size_t end2 = clock();

    // 计算两个函数运算完成之后的时间
    cout << "TestFunc1 time:" << end1 - begin1 << endl;
    cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

        通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。

6.引用和指针的区别

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

int main()
{
    int a = 10;
    int& ra = a;

    cout<<"&a = "<<&a<<endl;
    cout<<"&ra = "<<&ra<<endl;

    return 0;
}

  在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{
    int a = 10;

    int& ra = a;
    ra = 20;

    int* pa = &a;
    *pa = 20;

    return 0;
}

我们来看下引用和指针的汇编代码对比

 引用和指针的不同点

🔴引用概念上定义一个变量的别名,指针存储一个变量地址。
🔴引用在定义时必须初始化,指针没有要求
🔴引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
🔴没有NULL引用,但有NULL指针
🔴在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
🔴引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

🔴有多级指针,但是没有多级引用

🔴访问实体方式不同,指针需要显式解引用,引用编译器自己处理
🔴引用比指针使用起来相对更安全

 二、内联函数

1.内联函数的概念

        以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

 如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的
调用。

2.内联函数的特性

⭕inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
用函数体替换函数调用。

缺陷:可能会使目标文件变大

优势:少了调用开销,提高程序运行效率。

inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。

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

3.宏与内联函数

宏的优缺点

🔴优点:

        1.增强代码的复用性。 

        2.提高性能。

🔴缺点:

        1.不方便调试宏。(因为预编译阶段进行了替换)

        2.导致代码可读性差,可维护性差,容易误用。

        3.没有类型安全的检查 。

在C++中代替宏的方法

1. 常量定义换用const enum

2. 短小函数定义换用内联函数

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

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

相关文章

RocketMQ教程-(5)-功能特性-顺序消息

顺序消息为 Apache RocketMQ 中的高级特性消息&#xff0c;本文为您介绍顺序消息的应用场景、功能原理、使用限制、使用方法和使用建议。 应用场景​ 在有序事件处理、撮合交易、数据实时增量同步等场景下&#xff0c;异构系统间需要维持强一致的状态同步&#xff0c;上游的事…

13.4.2 【Linux】sudo

相对于 su 需要了解新切换的使用者密码 &#xff08;常常是需要 root 的密码&#xff09;&#xff0c; sudo 的执行则仅需要自己的密码即可。sudo 可以让你以其他用户的身份执行指令 &#xff08;通常是使用 root 的身份来执行指令&#xff09;&#xff0c;因此并非所有人都能够…

Spring 多数据源方法级别注解实现

Spring框架提供了多种数据源管理方式&#xff0c;其中多数据源管理是其中之一。多数据源管理允许应用程序使用多个数据源&#xff0c;而不是只使用一个数据源&#xff0c;从而提高了应用程序的灵活性和可靠性。 多数据源管理的主要目的是让应用程序能够在不同的数据库之间切换&…

SpringCache 框架使用以及序列化和缓存过期时间问题的解决

目录 为什么使用Spring Cache 如何使用Spring Cache 1 加依赖 2 开启缓存 3 加缓存注解 序列化以及过期时间等问题 解决方案&#xff1a;自定义序列化方式 1.自定义序列化方式并设置白名单 2.配置并设置缓存的过期时间 为什么使用Spring Cache 缓存有诸多的好处&#x…

YOLOv5(v7.0)网络修改实践二:把单分支head改为YOLOX的双分支解耦合head(DecoupleHead)

前面研究了一下YOLOX的网络结构&#xff0c;在YOLOv5(tag7.0)集成了yolox的骨干网络&#xff0c;现在继续下一步集成YOLOX的head模块。YOLOX的head模块是双分支解耦合网络&#xff0c;把目标置信度的预测和目标的位置预测分成两条支路&#xff0c;并验证双分支解耦合头性能要优…

为什么视频画质会变差,如何提升视频画质清晰度。

在数字时代&#xff0c;视频已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着视频的传输和处理过程中的多次压缩&#xff0c;画质损失逐渐凸显&#xff0c;影响了我们对影像的真实感受。为了让视频画质更加清晰、逼真&#xff0c;我们需要采取一些措施来保护和修复视…

设计模式大白话——观察者模式

文章目录 一、概述二、示例三、模式定义四、其他 一、概述 ​ 与其叫他观察者模式&#xff0c;我更愿意叫他叫 订阅-发布模式 &#xff0c;这种模式在我们生活中非常常见&#xff0c;比如&#xff1a;追番了某个电视剧&#xff0c;当电视剧有更新的时候会第一时间通知你。当你…

Zia和ChatGPT如何协同工作?

有没有集成ChatGPT的CRM系统推荐&#xff1f;Zoho CRM已经正式与ChatGPT集成。下面我们将从使用场景、使用价值和使用范围等方面切入讲述CRMAI的应用和作用。 Zia和ChatGPT如何协同工作&#xff1f; Zia和ChatGPT是不同的人工智能模型&#xff0c;在CRM中呈现出共生的关系。 …

荧光信号采集的2种方法

本文介绍荧光信号采集的2种方法。 荧光信号采集是生化类医疗设备&#xff08;PCR&#xff0c;荧光免疫分析仪&#xff09;常用的功能&#xff0c;针对不同类型的激发光和发射光采用的荧光信号采集方法也不一样。 1.基本概念 1)发光原理 当待测物质受到外接某一波长的入射光…

生物信息学_玉泉路_课堂笔记_02 第二章 序列比对和序列数据库搜索

&#x1f345; 课程&#xff1a;生物信息学_玉泉路_课堂笔记 中科院_2022秋季课 第一学期 &#x1f345; 个人笔记使用 &#x1f345; 2023/7/5 一、上周回顾 二、生物信息学的展望 —— 精准医学的发展 生物信息学的开拓者 三、双序列比对的常用算法 序列比对的需求 使用 b…

基于包围框回归的目标检测网络原理及Tensorflow实现

对象检测是对图像内的对象进行分类和定位。 换句话说&#xff0c;它是图像分类和对象定位的结合。 构建用于图像分类的机器学习模型更简单&#xff0c;我在我的一篇文章中对此进行了描述。 然而&#xff0c;图像分类器无法准确判断对象在图像内的位置。 为了实现这一目标&#…

opencv对相机进行畸变矫正,及从矫正后的图像坐标反求原来的对应坐标

1.背景 目前有个项目&#xff0c;需要用到热成像相机。但是这个热成像相机它的畸变比较厉害&#xff0c;因此需要用标定板进行标定&#xff0c;从而消除镜头畸变。 同时需要实现用户用鼠标点击矫正后的画面后&#xff0c;显示用户点击位置的像素所代表的温度。 2.难点 消除镜…

1-1 AUTOSAR是什么?

目录 一、AUTOSAR组织 二、AUTOSAR的版本 三、AUTOSAR的理念 四、AUTOSAR的动机 五、AUTOSAR目标 六、AUTOSAR的优势 6.1 商业优势 6.2 技术优势 一、AUTOSAR组织 AUTOSAR&#xff08;Automotive Open System Architecture&#xff09;是一个全球性的汽车行业标准化组织…

【流形和流形空间(姿态)】

定义 流形&#xff08;Manifold&#xff09;是一种广义的曲面概念&#xff0c;用于描述局部上类似于欧几里德空间的空间。简而言之&#xff0c;流形是一个局部与欧几里德空间同胚&#xff08;homeomorphic&#xff09;的空间&#xff0c;但并不一定是全局上同胚的。&#xff0…

Springboot项目打包war配置详解

Springboot项目打包war配置详解 1. 排除内置tomcat依赖2. 添加servlet依赖3. 修改打包方式4. 修改主启动类5. 完整pom.xml6. 效果图 1. 排除内置tomcat依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter…

Keil系列教程08_Configuration(二)

1写在前面 本文接着上一篇文章《Keil系列教程07_Configuration&#xff08;一&#xff09;》讲述的工程目标选项的后三项配置&#xff1a;Shortcut Keys快捷键、Text Completion代码完形、Other其他。 这后面三部分内容在该系列教程其它也会牵涉&#xff0c;也是一些常用、重要…

【数字信号处理】带通采样定理及其MATLAB仿真

目录 一、带通采样定理1.1 内容1.2 公式推导 二、MATLAB信号仿真2.1 信号仿真实验2.2 MATLAB代码 三、总结参考 一、带通采样定理 按照奈奎斯特采样定理(低通采样)&#xff0c;采样频率 f s f_{s} fs​ 要大于等于信号中最高频率 f m a x f_{max} fmax​ 的2倍&#xff0c;才…

excel导入,错误数据excel导出

要实现功能&#xff0c;非空校验&#xff0c;如果为空 则下载错误excel&#xff0c;说明错误原因 导入实体 Data AllArgsConstructor NoArgsConstructor public class ExcelDto implements Serializable{/*** 用户名*/ExcelProperty("用户名")private String user…

JVM系统优化实践(22):GC生产环境案例(五)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 除了Tomcat、Jetty&#xff0c;另一个常见的可能出现OOM的地方就是微服务架构下的一次RPC调用过程中。笔者曾经经历过的一次OOM就是基于Thrift框架封装出来的一个RPC框架导…

SAP中文界面乱码问题的分析处理实例

近期遇到用户反映主题问题&#xff0c;如下图这样的中文乱码在SAP的菜单和功能界面中随处可见。 经过一系分析检查发现导致问题的原因在于操作系统中的区域格式语言设置&#xff0c;这里用户设置是中文&#xff0c;简体汉字&#xff0c;香港特别行政区。将其变更为中文&#xf…