七、引用
(一)引用 概念
(1)引用 概念
引用不是新定义一个变量,而是给已存在变量取了一个别名
编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 。
就好比 鲁迅 和 周树人 是同一个人。
(2)引用 使用
引用就是取别名;
类型 &
引用变量名(对象名) = 引用实体;
【★☆★ 注意:引用类型 必须和 引用实体 是 同种类型 的】
在这里插入代码片
★☆(3)引用 特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
别名也可以再取别名
也可对常量进行别名
- 引用一旦引用一个实体,再不能引用其他实体
定义了是一个实体的别名,就不能再改变成其他实体的别名了 。
- C++中无法通过
=
符号,将引用一个实体得到的别名,更改为另一实体的别名。 - 但Java中可以 通过
=
符号,改变别名的引用的方向。
所以,别名不能完全替代指针,更多的是 别名 与 指针配合使用
(4)常引用
//常引用 int main(){ const int a = 10; int& b = a; return 0; }
大家可以去自己的编译器下运行一下这段代码,看看会出现什么问题
详解
- const 修饰:
- 可做 const修饰的 变量的别名 (权限可平移)
- 也可做 非const修饰的 变量的别名(权限可缩小)
- 指针也同样存在权限放大缩小的问题:
const + 指针 也不能传给 非const的指针 去保存。(在const修饰下,还存在可修改的可能,这是不合法的) - 总结:
权限可平移,可缩小,但不能放大 。
这里则是 定义了另外一个变量空间b,将a的值赋值给b,对值的拷贝,对a的权限没有影响,所以是合法的。
(二)引用的 实际应用 及 其意义
也正是因为别名和它引用的变量 共用同一块内存空间这一特性,所以 取别名就跟把地址传过去一样,改变的内存空间都是同一块。为后文,做参数时,大大提高了写代码的效率【请看下文】
☆(1)做参数 —— &形参取别名 可做到 形参的改变可影响实参
☆★ 1.1 传值、传引用效率比较
- 传值
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝 。
因此用值 作为参数或者返回值类型,效率是非常低下的,尤其是当 参数或者返回值类型 非常大 时,效率就更低。
- 传引用 = 传指针(且还会比传指针更方便)
正是因为 别名和它引用的变量 共用同一块内存空间这一特性,所以 取别名就跟把地址传过去一样,改变的内存空间都是同一块。
所以,对 传过来的参数取别名(作为形参) = 在 解引用*
实参的地址,直接对实参的地址进行操作,不需要再拷贝内容了 。
1.2 传值、引用传参 性能测试对比
(2)做返回值
问题一:下面代码输出什么结果?为什么?
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; }
答案是 3,7;
解析
★ 讨论:传引用返回值时 的函数调用完后栈帧销毁,收回空间使用权后是否还能找到数据 问题
- 在传值返回中,传回去的是 n值的拷贝
- 而在传引用返回中,则是 相当于 引用n取了个别名tmp(别名与实体 共用同一块空间,地址相同),把tmp传回去,相当于就是把n传回去(因为地址相同)。
☆ 但会出现类似野指针的问题,因为函数调用完了,函数开辟的栈帧就被销毁了,空间的使用权被操作系统收回,但空间还在,操作系统继续运行程序时,再重新将这块空间进行分配,重复利用。
所以 返回的是多少取决于:
- 编译器是否在销毁栈帧时清理n的空间
- 以及,是否在空间使用权收回后,分配给下一个程序,是否有程序运行产生的数据将其要返回的原空间 变量n储存的数值 覆盖
【函数栈帧的调用与销毁 不懂的同学建议去看一下这篇文章,了解其底层原理,能帮助我们更好的掌握知识,串联知识。】
改进:用 static 进行修饰,出了作用域,对象还在(合法化),才能引用返回
- 问题二:那要是把条件改为 static int c = a + b;和 结果又会发生什么变化呢
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; Add(3, 4); cout << "Add(1, 2) is :"<< ret <<endl; return 0; }
- 问题三:static int c; c = a + b; 值又是多少呢?
int& Add(int a, int b) { static int c; 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; }