C++入门:引用、内联函数、auto关键字

目录

一:引用

(1)概念

(2)使用

(3)引用的特性

(4)引用的使用场景

【1】做参数

【2】做返回值

(5) 引用的权限问题

(6)引用和指针的区别

【1】引用的底层实现

【2】指针和引用的一些不同

二:内联函数

(1)宏函数

【1】 宏的优点

【2】宏的缺点

(2)内联函数的使用

(3)观察内联函数是否展开

三:auto关键字

(1)概念

(2)实际的应用场景

【1】类型名过长,过于复杂

【2】基于范围的for循环(C++11)

(3)使用时的几个注意点

【1】auto的使用细则

【2】auto也有无法推导的场景

四:指针空值nullptr(C++11)

(1)C++98标准下的指针空值

(2)C++11中的nullptr

五:杂谈


一:引用

(1)概念

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


(2)使用

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


(3)引用的特性

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

       一个变量可以有多个引用

       引用一旦引用一个实体,就无法再引用其他实体


(4)引用的使用场景

【1】做参数


【2】做返回值

在讲这个内容之前,我先带大家复习一下内存空间。

传引用做返回值可以理解直接返回了这个变量。

我们看下面两个例子

 ②

 

 注意:②的情况不同操作系统结果可能不一样(可能栈区回收后会立刻刷新),是标准的未定义行为,而且使用未申请的空间本身就是非法的。


(5) 引用的权限问题


(6)引用和指针的区别

【1】引用的底层实现

引用从语法的角度看好像没有开辟空间,和引用对象共享一片空间,但是在底层实现上引用是有空间的,因为引用是用指针实现的

将这一段代码转化为汇编代码 

 ⭐由此我们可以看出引用本质就是一个指针,但是初始化后无法进行更改由编译器实现解引用


【2】指针和引用的一些不同

其实理解了引用的底层实现后可以依据个人的理解去总结两者不同点,不需要所谓的背诵,我这里就简单的罗列几点:

           ①引用定义时必须初始化,指针没有硬性要求

           ②引用初始化后无法引用其它实体,指针可以修改指向

           ③在sizeof中含义不同,引用为引用的实体的大小,指针为4(32位)或8(64位)字节。

           ④访问实体的方式不同,指针需要手动解引用,引用由编译器实现。

           ⑤引用的使用比指针更加安全

           ⑥语法上引用是给实体取了一个变量,而指针则是保存了实体的空间地址。

           ⑦引用加1是实体加1,指针加1是向后偏移一个所指向类型的大小。

           ⑧有多级指针,但是没有多级引用,下面的代码都是a的引用。


二:内联函数

(1)宏函数

在讲内联函数之前,我先带大家复习一下C语言中的宏函数

(为和函数进行区分,后面简称宏)。


【1】 宏的优点

            ①只是进行单纯的替换不会像函数调用那样开辟栈帧,效率更优。

            ②单纯替换,没有类型检查,面对不同数据类型可能会有优势。

            ③提高代码复用性


【2】宏的缺点

           宏无法调试

           ②只是单纯替换,没有类型检查,不安全。

           ③复用次数很多的情况,可能会导致程序变大。

这里重点讲一下③:

宏只是普通替换,函数是有具体空间的,也就是说你使用100w次Add功能,宏的话要进行100w次替换,函数的话虽然也要调用100w次,但调用的一直是同一个函数。

实现了同样的功能,虽然宏函数效率可能会优一点,但指令数太多,可能导致程序过大。 


(2)内联函数的使用


(3)观察内联函数是否展开

⭐在debug版本下编译器不会进行优化,无论指令多少内联函数都会像正常函数一样调用(目的是为了方便调试),如果想观察是否展开的话,要进行设置。

设置完毕后,按下f10进入调试,右击转到反汇编。

观察调用Add1和Add2函数的汇编代码。

只是观察这个现象,不需要对汇编代码很熟悉。

⭐最后强调一下,基于内联函数的特殊性质,内联函数在汇编时是不会进符号表的,声明定义不要分离,分文件的情况下直接在头文件中进行定义。

(头文件和源文件没有本质区别)


三:auto关键字

(1)概念

auto早期的含义(了解即可):使用auto修饰的变量,是具有自动存储器的局部变量(变量由编译器自动分配和释放,在函数被调用时分配内存,在函数执行结束时释放内存),但是很少有人使用。


C++11中auto被赋予了新的含义:auto不再是存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto定义的变量必须由编译器在编译时期推导而来。

(一句话就是auto定义的变量编译器会依据变量所接收的值来推导变量的类型)


(2)实际的应用场景

【1】类型名过长,过于复杂

⭐像这种情况,我们就可以用auto进行类型的自动推导


【2】基于范围的for循环(C++11)

C++98:

C++11:


范围for的使用条件

  1. for循环迭代的范围必须是确定的 

 2. 迭代的对象要实现++==的操作(涉及到迭代器,没办法展开讲,先了解)


(3)使用时的几个注意点

【1】auto的使用细则



【2】auto也有无法推导的场景



四:指针空值nullptr(C++11)

(1)C++98标准下的指针空值

 ⭐空指针应该也要是一个指针才对,但是C++中却是一个常量0,这在某些情况下可能会产生不必要的麻烦。


(2)C++11中的nullptr

nullptr实际上就是((void *)0),使用nullptr代替NULL可以避免不必要的麻烦。

注意:

         使用nullptr不需要包头文件,nullptr在C++11中作为关键字引入

         ②C++11中,sizeof(nullptr) sizeof((void*)0)所占的字节数相同。

         ③为了提高代码的健壮性,在C++中表示指针空值时建议最好使用nullptr


五:杂谈

这两期的内容其实是在为后面学习C++做一个铺垫,所以不得不暂时忽略一些内容,如果都展开讲的话,我估计没个几万字是讲不完的,大家也不乐意看。

附上一期链接:https://blog.csdn.net/2301_76269963/article/details/130990304?spm=1001.2014.3001.5502


讲几个我自己的观点(我也只是初学者,欢迎各位大佬指正):

①学习C/C++没法避开底层,但并不意味着需要完全掌握底层


②更多的时候是建立一个抽象区,由这个抽象区去链接底层,确保这个抽象区是大体正确,自己所能够理解和接受的。

(就像内存空间我知道分成栈区、静态区、堆区、常量区等等,但是我并不知道系统是怎么分配这些空间的;我知道汇编代码的大意,但我不会写汇编代码,从学习语言的角度也不需要很明确。)


③有的时候必须选择性的忽略一些细节,才能够继续往下学。

(如果一开始接触了C++的输入输出,我就马上想知道它的原理,不可避免的会涉及到类和对象、IO流、运算符重载等等,很容易入门到放弃)

猜你喜欢

转载自blog.csdn.net/2301_76269963/article/details/131022258