引用
概念
引用,就是给一个变量起别名。通过使用引用变量就可以拿到其所引用的空间。
变量类型 + & 就定义了一个引用。
int&
,这就是整型变量的引用。
引用的理解
好多地方建议将引用理解为是一个变量的别名,可我总感觉这样不太恰当。于是冥思苦想,终于找到了一个我认为更加恰当的理解方式。将每一个变量视为笔记本中的一页,引用视为是笔记本每一页上贴的的tag标签,每创建了一个引用,就相当于创建了一个tag,然后将一个变量赋值给这个引用的操作就是,将这个tag贴在这个变量上。
这样,每当使用引用变量的时候,因为它是一个tag,所以就能轻松地找到其所贴的变量,进而就能使用这个变量了。
引用需要注意的地方
- 引用在定义的时必须及进行初始化,不初始化的话这个标签就是个废标签了,自然就是一个bug
- 一个变量可以有多个引用,当然可以贴多个标签了
- 引用一旦成为了其他实体的引用,则不能再成为其他实体的引用。标签贴上去以后就不能揭下来了。
对于向引用变量赋值的理解
- 当左值是一个引用的时候,此时对于右值的拿取方式为直接拿到这块空间,然后,引用成为这块空间的别名
- 当左值不是引用的时候,此时对于右值的拿取方式为拿到这块空间的数据,然后将数据赋值给左值变量
引用的底层实现
底层实现:
引用实质是通过常指针实现的(知道即可,不必深究)
对于临时变量的理解
- C++在处理表达式计算、函数返回值、变量类型转换等都会将计算结果存放到一个临时变量中。
- 临时变量具有常属性,不可以被修改,故只能作为右值。
- 小的临时变量会存放到寄存器中,比较大的临时变量会存放到函数栈帧中。
引用的使用
-
引用做参数
- 如果函数中不改变参数的值,建议使用const引用
-
引用做返回值
- 引用返回可能会导致非法空间的访问,故不要返回局部变量的引用。
- 如果函数返回的时候,出了函数作用域,如果返回的对象还在(还没有返回给操作系统),则可以使用引用返回;如果已经返回操作系统,则必须使用传值返回,以防止非法访问空间
- 当函数调用完成后,会将返回值 ,也就是引用变量,放到一个临时变量里面,然后通过这个临时变量就可以找到它所引用的空间
- 引用返回的价值:
- 提高效率
- 修改返回变量
-
引用在函数重载中应注意:
C++单纯由于引用传递和值传递的方式造成的参数列表不同,理论上是可以构成函数重载的,但是在调用函数的时候会具有二义性,编译器无法判断是调用引用传递还是值传递,所以会链接失败,同样会报错。
常引用
// 权限放大 不可以
const int a = 10;
int& b = a;
//权限不变 可以
const int a = 10;
const int& b = a;
//权限缩小 可以
int a = 0;
const int& b = a;
//const 引用大小通吃
在发生类型截断和提升的时候,是将结果放在一个临时变量里面的,临时变量具有常属性
double a = 1.11;
int& b = a; // 这样会报错,因为会发生截断,会有一个临时变量,临时变量具有常属性,所以要用常引用来接
const int& b = a; // 这样就对了
引用和指针的区别
- 引用在概念上就是一个变量的别名,指针则是存储一个变量地址的变量
- 引用在定义时必须初始化,而指针可以不用
- 引用一旦被初始化,就不能够改变指向,而指针可以在任何时候指向任意的同类型实体的地址
- 没有NULL引用,但有NULL指针;使用指针要考虑空指针和野指针等等问题,因此指针太灵活了,所以相对而言,引用更加安全
- 引用一旦被初始化,就不能够改变指向,而指针只要不是常指针就可以随时改变指向。
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理