【C++】引用、内联函数、auto关键字等

前言:在前面我们讲解了C++入门基础的一些学习例如命名空间、缺省参数、函数重载等。今天我们将进一步的学习,跟着博主的脚步再次往前迈一步吧。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:高质量C++学习 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


  • 目录标题

    • C++入门
      • 引用
        • 引用的特性与引用的使用
          • 引用的使用
          • 变量与引用的变量共用同一块内存空间
          • 引用的特性
        • 常引用
        • 引用的使用场景
          • 做参数
          • 做返回值
      • 内联函数
        • 内联函数的特性
        • 内联函数的限制和注意事项
          • 基于范围的for循环(C++11)
        • 指针空值nullptr(C++11)

C++入门

引用

C++中引用是一种特殊的变量类型,它类似于一个别名,可以用来引用另一个变量。引用用&符号来声明,对于一个已经存在的变量,可以使用引用来访问该变量的值。如果我们还是无法理解什么是引用,我们可以通俗的理解成,你的名字叫张三,但是你的小名叫三三、阿三等等,无论小名是什么,这个名字的本质都是指代着你这个人。
语法说明:类型& 引用变量名(对象名) = 引用实体

引用可以有以下特点

  1. 引用必须在声明时初始化,并且不能改变引用的目标。一旦指定了引用的目标,它将始终引用该目标。

  2. 引用可以用来修改引用的目标。通过引用可以修改引用所指向的变量的值。

  3. 引用不能引用空值或不存在的对象。

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

  5. 不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。


引用的特性与引用的使用

引用的使用
int main() {int x = 10;int& ref = x;//对x进行引用cout << "x = " << x << endl; // 输出 x = 10cout << "ref = " << ref << endl; // 输出 ref = 10ref = 20; // 修改引用的目标cout << "x = " << x << endl; // 输出 x = 20cout << "ref = " << ref << endl; // 输出 ref = 20return 0;
}

在这里插入图片描述


变量与引用的变量共用同一块内存空间
void TestRef()
{int a = 10;int& ra = a;//<====定义引用类型printf("%p\n", &a);printf("%p\n", &ra);
}int main()
{TestRef();return 0;
}

在这里插入图片描述
此时我们也不难发现,a和ra所在的空间上的地址是相同的,因此可以知道,a和ra共用同一块内存空间。
在这里插入图片描述


引用的特性

如果要博主解释引用的话,博主目前短暂的理解是,引用如指针是十分相向的,但是引用一旦指向一个实体就不能改变其指向了。

  1. 引用在定义时必须初始化

  2. 一个变量可以有多个引用

  3. 引用一旦引用一个实体,再不能引用其他实体

int main()
{int a = 10;int& ra = a;//int& ra;此时会报错,因为引用在定义的时候必须初始化int& rra = ra;//一个变量可以拥有多个引用cout << "原本的值" << endl;cout << "a = " << a << " ra = " << ra << " rra = " << rra << endl;//引用的变量与变量本身共用同一块空间cout <<"地址: " << "a = " << &a << " ra = " << &ra << " rra = " << &rra << endl;cout << "修改后的值" << endl;a++;//对引用的修改是会影响变量本身的ra++;rra++;cout << "a = " << a << " ra = " << ra << " rra = " << rra << endl;cout << "地址: " << "a = " << &a << " ra = " << &ra << " rra = " << &rra << endl;return 0;
}

在这里插入图片描述


常引用

const这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。和const修饰变量一样,被const修饰的引用只能够读,而不能够写,即不能修改引用变量的值。接下来我们将通过几个例题来帮助我们理解,如下:

例1:请问如下两个语句,哪一个会报错,哪一个不会。

 const int a = 10;//语句1int& ra = a;  //语句2

代码解读:

在如上的两个代码中,语句1将10这个常量传给了整型a,并且a无法被修改,因此语句1正确,而语句二,我们将一个无法被修改的a值传给引用ra,此时我们不难发现,如果ra可以这样引用的话不就代表a值是可以修改的了嘛?那这个const修饰的a不就没有任何意义了嘛?因此不难判断出语句2是错误的。因此正确的写法是:const int& ra = a; 此时我们用const修饰的引用变量ra就可以达到该引用值无法被修改。


例题2:请问如下两个语句,哪一个会报错,哪一个不会。

int& b = 10; //语句1
const int& b = 10;//语句2

代码解读:

我们可以知道10是一个常量对吧,10能被修改嘛?当然不可以,因此我们怎么可能可以通过引用变量直接来引用10呢?这不开玩笑嘛,如果b能够直接修改这个10,那10是什么表示呢?如果不懂的可以看下图。那么语句2呢?我们用const修饰引用变量,那么此时被引用的变量就无法修改,因此语句2正确。

在这里插入图片描述


例题3:请问如下两个语句,哪一个会报错,哪一个不会。

 double d = 12.34;int& rd = d; //语句1const int& rd = d;//语句2

代码解读:

语句1直接对d进行引用的同时,在编译器中会对d进行强转成一个整型12,而12具有常性因此如果我们直接对其进行引用的过程中会导致我们墙面讲到的情况,如果对一个常量直接引用会导致数据发生修改,因此我们需要加上const对其进行修饰,如果不能理解可以看下图。

在这里插入图片描述
整体代码测试:

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;cout << "a = " << a << " ra = " << ra << " b =  " << b << " d = " << d << " rd = " << rd << endl;
}int main()
{TestConstRef();return 0;
}

运行结果
在这里插入图片描述


引用的使用场景

做参数

在学习C语言的过程中我们知道,如果将一个数传递给函数,形参是实参的一份临时拷贝,此时空间占用是十分大的,而引用本质就是直接把该数本身传递过去,直接对这个数可以进行修改省区了对该数进行拷贝的过程减少了空间的消耗.
实例演示

void Swap(int& a, int& b)//此时我们直接用引用结接收
{int tmp = 0;tmp = a;a = b;b = tmp;
}int main()
{int n = 3;int m = 4;cout <<"修改前: " << n << ' ' << m << endl;Swap(n, m);cout <<"修改后: " << n << ' ' << m << endl;return 0;
}

在这里插入图片描述

具体等作为参数的情况,我们在后面的学习会持续体会到的,到时候感受肯定是会与现在不太一样,因此我们现在就对其做一个初步的使用即可.


做返回值

我们接下来依然通过几个例子来帮助我们理解作为返回值的情况.
例1:

int& Func()
{static int n = 0;//static修饰的局部变量出了作用域不会结束n++;printf("&n:%p\n", &n);return n;
}int main()
{int ret = Func();cout <<"n = "<< ret << endl;//查看此时n的地址与值int& rret = Func();printf("&rret:%p\n", &rret);return 0;
}

此时我们不难发现将引用作为返回值返回给了函数
在这里插入图片描述


例题2:

int& Add(int a, int b)
{static int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);cout << "Add(1, 2) is :" << ret << endl;int& m = Add(3, 4);cout << "Add(3, 4) is :" << m << endl;return 0;
}

代码分析:
这里我们将1,2先传过去因此一开始返回的是3没有任何疑问,在第二次传递给3和4的时候我们需要注意达到是static修饰的局部变量出了作用域并不会结束,static修饰局部变量会进行一次初始化,并且只会进行一次,因此我们传过去的3和4并没有相加,返回的依然是上一次的结果3.
在这里插入图片描述


例题3:

int& Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);cout << "Add(1, 2) is :" << ret << endl;Add(3, 4);cout << "Add(1, 2) is :" << ret << endl;return 0;
}

代码分析:
在函数 Add 中,局部变量 c 的生命周期仅限于函数内部。
当函数执行完毕后,c 被销毁,而返回的引用 ret 将指向一个不存在的对象。当再次使用这个引用时,就会出现未定义的行为。因为此时我们又传递了3和4此时我们并没有返回值接收,然后再次调用ret的时候所引用的就是3和4那块函数所指向空间的值.
在这里插入图片描述
总结一下:出了函数作用域返回变量不存在了,不能用引用返回因为此时指向的空间已经被销毁了可以理解成为一个野引用,因此出了函数作用域返向变量存在,才能用引用返回.

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

内联函数

C++内联函数是一种特殊的函数,其函数体在调用点处直接展开,而不是按照函数调用的方式进行执行。这样可以避免函数调用的开销,提高程序的执行效率。
在C++中,可以通过将函数定义放在函数声明之前,并在函数声明处加上关键字“inline”来定义内联函数

内联函数的特性

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
    用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
    行效率。
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

内联函数的限制和注意事项

  1. 内联函数的定义必须在每个使用该函数的文件中可见。
  2. 内联函数一般放在头文件中,以便在多个源文件中使用。
  3. 内联函数不应包含复杂的逻辑或大量的代码,以避免代码膨胀。
  4. 对于递归函数、带有循环或开销较大的函数,不建议使用内联函数。

实例演示:

inline int add(int a, int b) //内联函数的定义
{return a + b;
}int main()
{cout << add(19, 21) << endl;return 0;
}

在这里插入图片描述


auto 关键字在C语言中就已经存在了,只不过在C语言中它的作用是声明自动变量:auto int a = 0;
在C++中,关键字auto用于自动推导变量的类型。它可以让编译器根据变量初始化表达式的类型自动推导出该变量的类型,从而简化变量类型的声明和初始化过程

使用auto关键字有以下几点注意事项:

  1. auto关键字只能在变量的声明和初始化过程中使用,不能用于函数的返回类型、函数参数类型、类成员的类型等。
  2. auto关键字通常用于推导变量的类型,不适用于推导引用或指针的类型。如果需要推导引用或指针的类型,可以使用auto&或auto*。
  3. 推导出的变量类型与表达式的类型是一致的,包括const、引用、指针等限定符。
  4. auto关键字在编译时自动推导变量类型,而不是在运行时进行类型推导。
    实例演示:
void func(int a, int b)
{//.....//.....
}int main()
{int i = 0;int j = i;auto k = i;//auto可以通过右边的类型自动推导左边的类型auto p1 = &i;void(*pf1)(int, int) = func;//函数指针auto pf1 = func;//用auto直接直接识别
}
基于范围的for循环(C++11)

在C++98中如果要遍历一个数组,可以按照以下方式进行:

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)array[i] *= 2;
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)cout << *p << endl;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。ps:目前我们只讲怎么用即可,以后会给大家详细讲解
实例演示:

int main()
{for (auto e : array)//依次取数组中的值赋值给e,自动迭代,自动判断结束{cout << e << " ";}
}	

在这里插入图片描述

int main()
{for (auto& e : array)//e是对数组里面的值的拷贝,所以无法直接赋值,得引用{e *= 2;}for (auto e : array){cout << e << " ";}
}

在这里插入图片描述


指针空值nullptr(C++11)

在这里我们只需要知道nullptr是替代原本的NULL即可

在C++中,nullptr是一种特殊的空指针常量。它被用来表示一个空指针,即指向没有任何对象的指针。
在早期的C++版本中,常常使用NULL来表示空指针。然而,NULL实际上是一个宏定义,一般被定义为整数0。这样的定义使得在一些情况下,NULL可能会被误用。
为了解决这个问题,C++11引入了nullptr。nullptr是一个关键字,用来表示空指针,不会被隐式地转换成其他类型。使用nullptr可以提高代码的可读性和安全性.总而言之,nullptr是C++11中用来表示空指针的关键字,相对于早期的NULL常量,nullptr更加安全和可读性更好.


好啦,今天的内容就到这里啦,下期内容预告类和对象


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🌏🗺️ 这里祝各位寒假愉快 💞💞

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

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

相关文章

万字长文扫盲JUC基础

文章源码地址 文章目录 JUC概述什么是JUC线程和进程的概念进程和线程线程的状态wait和sleep并发和并行管程monitor用户线程与守护线程 Lock接口复习Synchronizedsyschronized卖票案例多线程编程步骤 什么是Lock接口Lock接口的介绍Lock实现可重入锁实现卖票案例 线程间通信案例…

从云计算到物联网:虚拟化技术的演变与嵌入式系统的融合

文章目录 一、硬件性能提升&#xff1a;摩尔定律与嵌入式虚拟化二、CPU多核技术&#xff1a;为嵌入式虚拟化提供支持三、业务负载整合&#xff1a;嵌入式虚拟化的核心需求四、降低硬件成本&#xff1a;虚拟化技术的经济效益五、软件重用与移植&#xff1a;虚拟化技术的优势六、…

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏4(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言源码制作系统简单绘制制作系统面板UI斧头素材代码控制工具栏操作制作石斧 完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇…

C#用DateTime.Now.ToString方法将日期格式化为指定格式

目录 一、DateTime.Now.ToString方法 二、实例 一、DateTime.Now.ToString方法 调用DateTime对象的ToString方法可以将当前DateTime对象的值转换为其等效的字符串表示形式&#xff0c;而且ToString方法提供了重载&#xff0c;可以在ToString方法中添加不同的参数&#xff0c;…

JAVA编程语言单词汇总

Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发&#xff0c;并在 1995 年正式推出。后来 Sun 公司被 Oracle &#xff08;甲骨文&#xff09;公司收购&#xff0c;Java 也随之成为 Ora…

Android 基础技术——Bitmap

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于 Bitmap Bitmap 内存如何计算 占用内存 宽 * 缩放比例 * 高 * 缩放比例 * 每个像素所占字节 缩放比例 设备dpi/图片所在目录的dpi Bitmap加载优化&#xff1f;不改变图片质量的情况下怎么优化&am…

【一竞技DOTA2】Blacklist战队官宣租借Palos参加ESL伯明翰预选赛

1、Blacklist战队官宣租借Palos参加ESL伯明翰站最终预选赛。Palos自2022年2月份以来一直效力于同为东南亚赛区的Execration战队&#xff0c;这次租借是替补前不久刚刚离队的Raven。 2、俄罗斯未来运动会最近官宣nouns战队因故退出。另外还有Neon、Nigma&#xff0c;Entity&…

【Linux】第三十九站:可重入函数、volatile、SIGCHLD信号

文章目录 一、可重入函数二、volatile三、SIGCHLD信号 一、可重入函数 如下图所示&#xff0c;当我们进行链表的头插的时候&#xff0c;我们刚刚执行完第一条语句的时候&#xff0c;突然收到一个信号&#xff0c;然后我们这个信号的自定义捕捉方法中&#xff0c;正好还有一个头…

“值得一试的六个浏览器扩展推荐|让你的上网更加便捷和有趣!”

iTab新标签页(免费ChatGPT) iTab是新一代组件式标签页的首创者&#xff0c;简洁美观高效无广&#xff0c;是您打造个人学习工作台的浏览器必备插件。 详情请见&#xff1a; iTab新标签页(免费ChatGPT) - Microsoft Edge Addons AdGuard 广告拦截器 AdGuard 广告拦截器可有效的…

GD32移植FreeRTOS+CLI过程记录

背景 之前我只在STM32F0上基于HAL库和CubeMX移植FreeRTOS&#xff0c;但最近发现国产化替代热潮正盛&#xff0c;许多项目都有国产化器件指标&#xff0c;而且国产单片机确实比意法的便宜&#xff0c;所以也买了块兆易创新的GD32F303开发板&#xff0c;试一试它的优劣。虽然GD…

【Web前端实操17】导航栏效果——滑动门

滑动门 定义: 类似于这种: 滑到导航栏的某一项就会出现相应的画面,里面有对应的画面出现。 箭头图标操作和引用: 像一些图标,如果需要的话,可以找字体图标,比如阿里巴巴矢量图标库:iconfont-阿里巴巴矢量图标库 选择一个——>添加至购物车——>下载代码 因…

Facebook的智能时代:AI技术在社交中的崛起

随着科技的快速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经深刻改变了我们的生活方方面面&#xff0c;而社交媒体领域也不例外。在这个信息爆炸的时代&#xff0c;Facebook正以令人瞩目的速度推动着AI技术在社交领域的崛起。本文将深入探讨Facebook如何在智能…

STM32控制DS18B20温度传感器获取温度

时间记录&#xff1a;2024/1/28 一、DS18B20温度传感器介绍 &#xff08;1&#xff09;测温范围-55℃~125℃&#xff0c;在-10℃到85℃范围内误差为0.4 &#xff08;2&#xff09;返回的温度数据为16位二进制数据 &#xff08;3&#xff09;STM32和DS18B20通信使用单总线协议…

Nginx解析漏洞复现

首先这个漏洞不是软件或代码的问题&#xff0c;是认为疏忽造成的。 一、环境搭建 从vulhub上面下载vulhub-master.zip文件&#xff0c;上传到服务器中&#xff0c;或者直接在服务器下载。 unzip vulhub-master.zip 进入漏洞目录 cd /vulhub-master/vulhub-master/nginx/ng…

【electron】打包问题处理

目录 项目无法在win7执行场景尝试处理 项目无法在win7执行 场景 使用electron25.0.1、electron-builder24.2.1&#xff0c;打出来的项目在win7系统上跑不起来&#xff0c;报错无法定位程序输入点DiscardVirtualMemoty于动态链接库KERNEL32.dll上。 尝试处理 通过百度发现ele…

高分文献解读|乳酸通过与可溶性腺苷酸环化酶结合调控铁代谢

乳酸(LA)的过量产生可能发生在运动期间或者许多疾病中&#xff0c;例如癌症中。个人伴有高乳酸血症的患者常表现为贫血、血清铁减少以及一种铁代谢关键调控因子—铁调素&#xff08;hepcidin&#xff09;升高。然而&#xff0c;目前尚不清楚乳酸是否以及如何调节铁调素的表达。…

算法39:统计全 1 子矩形(力扣1504)----单调栈

题目: 给你一个 m x n 的二进制矩阵 mat &#xff0c;请你返回有多少个 子矩形 的元素全部都是 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[1,0,1],[1,1,0],[1,1,0]] 输出&#xff1a;13 解释&#xff1a; 有 6 个 1x1 的矩形。 有 2 个 1x2 的矩形。 有 3 个 2x1 的矩…

ERP定制费用怎么算?详解跨境电商成本控制策略

在全球化数字经济的浪潮中&#xff0c;跨境电商行业具有潜在的高利润和巨大的发展空间&#xff0c;吸引着众多创业者的关注和投入。然而&#xff0c;与潜在利润相伴随的是种种挑战&#xff0c;成本控制便是其中关键的一环。在这一行业中&#xff0c;ERP定制费用作为一个重要的成…

第十三章认识Ajax(四)

认识FormData对象 FormData对象用于创建一个表示HTML表单数据的键值对集合。 它可以用于发送AJAX请求或通过XMLHttpRequest发送表单数据。 以下是FormData对象的一些作用&#xff1a; 收集表单数据&#xff1a;通过将FormData对象与表单元素关联&#xff0c;可以方便地收集表…

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现 —— 杭州 2024-01-28 code review! 文章目录 C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现1.RTTI、RAII、MVC、MVVM、SOLID简述2.RAII (Resource Acquisition Is Initialization)3.RTTI (Run-Time Type Informat…