目录
6. 引用
6.1 什么是引用?
引用不是重新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
引用的使用格式:
变量类型& 引用变量名(对象名) = 引用实体;
我们可以发现两者地址是相同的。
注意:引用类型必须和引用实体是同种类型的,否则就会报错
6.2 引用特征
1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 一旦引用了一个主体就不能引用其他主体
我们可以发现当b在ra的右侧时,ra的地址没有改变,因此我们可以知道当引用了一个主体之后,之后都是赋值。
6.3 常引用
首先我们需要讨论下引用的权限:当发生引用后,引用的权限只能缩小而不能扩大。
主体相当于一个房间,引用相当于就是有了这个房间的使用权,但是有的房间它只让你住不让你进行装修,那我们需要怎么做呢?
我们只需要给引用前面加上const,用来限制我们的权限。
那之前我们谈论到引用和主体必须是同一个类型,这又是为什么呢?
因为不同类型的变量进行赋值时,会产生一个临时变量,该临时变量具有常量性,相当于我们的主体变成了一个常数,因此需要加上const。
6.4 引用的使用场景
1. 作为参数
2. 做返回值
我们可以发现传回来的是Add中临时变量的别名。
但是我们知道在函数调用时会开辟函数栈帧,离开后会销毁栈帧,那我们可以发现当前ret中现在指向的其实是一个被销毁了的空间,这是越界的一种行为。
因此如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
6.5 传值和引用的效率比较
我们可以很明显的看见引用比传值调用要快很多,这是因为什么呢?
因为传值调用时,会形成临时拷贝,实参越大,形参也越大,开辟的空间也越多,不仅会效率降低还会引起空间损耗。
而引用不需要拷贝,直径使用实参的空间进行操作。
6.6 引用和指针的区别
语法区别:
引用:就是一个别名,没有独立的空间,与主体共有一个空间
指针:有4/8个字节的独立空间
底层原理:
两者是没有区别的,因为引用是按照指针的方式构建的
通过指针和引用的汇编比较,我们发现在底层两者是相同的
那为什么要创建引用呢?
我们来看一看指针和引用的区别:
1. 引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
3. 没有NULL引用,但有NULL指针
4. 在sizeof中含义不同:引用结果为主体类型的大小,但指针始终是地址空间所占字节个数(32位平台下占 4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全,因为引用必须初始化不存在野指针一说
7. 内联函数
7.1 什么是内联函数
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开(类似于宏),没有函数压栈的开销, 内联函数提升程序运行的效率。
加上inline以后
加上了inline后没有了对函数的call,而是直接进行函数里的操作,就是把函数展开了。
我们发现内联函数其实就是宏的升级版。
1. 它能够控制参数的类型
2. 它不像宏,容易写出错
7.2 内敛函数的特征
1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等,编译器优化时会忽略掉内联。
我们可以发现当内联函数中有过多语句时,它将不会展开并且会按照普通调用函数的形成来执行,这就是编译器的自动优化。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,不会在符号表中出现,在链接中就会找不到。
宏的优缺点
优点:
1. 增加代码的复用性
2. 提高效率,比起函数,不需要进行函数的调用和栈帧等增加时间的操作
缺点:
1.不方便调试宏 (因为预编译期间进行了宏替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型方面的检查 。
继续努力!!