【C++初阶】C++入门(下)
🥕个人主页:开敲🍉
🥕所属专栏:C++🥭
🌼文章目录🌼
6. 引用
6.1 引用的概念
6.2 引用特性
6.3 常引用
6.4 使用场景
6.5 传值、传引用效率比较
6.6 引用和指针的区别
7. 内联函数
7.1 内联函数的概念
7.2 特性
8. 指针空值nullptr
6. 引用
6.1 引用的概念
引用不是定义一个新的变量,而是给一个已有的变量取别名,因此引用并不会开辟额外的空间,它跟它引用的变量共用一块空间。举个简单的例子:有个人名字叫张小明,在家里他爸妈给他取了一个小名叫明明,在学校同学们给他取了个名字叫小明,这里的明明和小明都可以理解为张小明的引用,它们所指向的对象都是张小明。
引用:类型 & 引用变量名 = 引用实体:
因为pa就是a,所以改变pa的值自然也就会改变a的值,因为操作pa就是在操作a:
注意:引用类型必须和引用对象是相同类型的!
6.2 引用特性
① 引动在定义时必须初始化,换句话说,引用必须指向一个对象,不能空引用
② 一个变量可以有多个引用,这点也很好理解,就像上面的张小明,在家里他爸妈叫他明明,在学校同学叫他小明:
③ 引用一旦指向了某个对象,则不能再更改引用的对象
6.3 常引用
① 权限放大:
由此可以知道权限放大是错误的,不合法的。
② 权限缩小:
由此可以知道权限缩小是合法的。
6.4 使用场景
① 做参数
在过去我们学习C语言时,想要将两个变量的值进行交换,我们写出的交换函数是这样的:
会不会觉得这样挺麻烦的,又要进行取地址操作&,又要进行解引用操作。
现在,我们学习了引用之后,我们就可以这样写:
能够这样写的原理就是上面说的,引用是对一个变量取别名,对这个别名的操作就是对变量本身的操作。
② 做返回值
6.5 传值、传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直
接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效
率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
6.6 引用和指针的区别
引用是变量的一个别名,并不会开辟额外的空间,它和它引用的对象共用一块空间,对引用的操作就是对变量的操作,属于直接操作,而指针是一块地址,它保存所指向对象的地址,因此指针开辟了额外的空间,对变量操作需要对指针解引用,因此属于间接操作。引用在定义时必须初始化,而指针初不初始化都行;不能出现空引用,可以出现空指针;在sizeof中引用的大小就是所指向对象类型的大小,而指针始终为地址所占的空间大小(32位平台下为4个字节);
总结:
① 引用概念上定义一个变量的别名,指针存储一个变量地址。
② 引用在定义时必须初始化,指针可以不初始化
③ 引用在指向了一个对象后不能再更改,而指针可以随便指向任何同一类型的对象
④ 不能出现空引用,可以出现空指针
⑤ 在sizeof中的含义不同:引用为指向对象类型的大小,指针固定为地址的大小(32位平台下为4个字节)
⑥ 对引用的操作就是对变量的直接操作,指针对变量操作需要解引用,属于间接操作
⑦ 引用比指针使用起来相对更加安全
7. 内联函数
7.1 内联函数的概念
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方将其展开(不是一定的,这取决于编译器是否将其看作内联函数),没有函数调用建立的栈帧开销,因此内联函数提升了运行的效率。
如上图,没有使用内联函数时,反汇编中会有一句call指令,这说明编译器为这个函数开辟了一块栈帧,产生了空间的消耗。
如上图,使用内联函数后,编译器会将内联函数展开,因此没有了栈帧的创建。
7.2 特性
① inline是一种以空间换时间的做法,如果编译器将函数当作内联函数处理,在编译阶段,编译器会将内联函数展开。缺陷:可能会使代码量变大;优点:少了栈帧的创建,提高了运行效率。
② inline对于编译器来说只是一种建议,编译器是否会将其看作是内联函数取决于编译器本身,不同的编译器判断不一样。一般:当函数规模较小、非递归、函数频繁调用时可以采用inline修饰,否则编译器可能不会将其看作为内联函数。下图为《C++ Prime》第五版对inline的建议:
③ inline不建议声明和定义分离,如果将inline的声明和定义分离会导致链接错误。因为当inline被展开后就没有了地址(没有开辟栈帧),链接时就找不到它。
8. 指针空值nullptr
在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现
不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下
方式对其进行初始化:
NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
可以看到,在C++中,NULL为常量0;在C语言中,NULL为void*类型的常量。但是无论是哪种形式,在使用NULL时都不可避免会遇到一些麻烦,比如:
可以看到,func(NULL)的调用初衷是想调用第二个func,但是却调用了第一个,这就产生了歧义。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void
*)0。
因此在C++中,我们最好使用nullptr关键字来替代NULL。nullptr是专门用于指针类型的指针,而NULL即能代表常量0,又能代表(void*)类型的常量,出现歧义。
注意:
① 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为关键字引入的。
② 在C++11中,sizeof(nullptr)与sizeof((void*)0)所占字节大小相同。
③ 为了提高代码的健壮性,在后续表示指针空指时最好都使用nullptr。
创作不易,点个赞呗,蟹蟹啦~