目录
一.引用的概念
二.引用的特性
三.常数引用,类型不同如何引用
四.引用作为函数参数
五.引用作为函数返回值
六.引用与指针的区别
一.引用的概念
引用不是重新定义一个变量,而是给一个已经存在的变量取了 “别名”。
从使用角度来看,引用变量没有独立空间,并不会开辟内存空间,和其引用实体共用同一块空间;
从底层实现来看,引用变量实际是有空间的,因为引用是按照指针的方式实现的。
语法:
类型& 引用变量名 = 引用实体;
int a = 10; int& b = a;
二.引用的特性
1.引用在定义时必须初始化
2.一个变量可以有多个引用
3.引用变量只能有一个引用实体
int a = 10; int& b;//因为没有初始化,所以直接报错 int& c = a;//正确操作,c成为了a的别名 int& d = a;//正确操作,c是a的别名,d也是a的别名 int b = 20; c = b;//容易误解成:将c改为b的别名。 //注意:一旦一个引用变量引用了引用实体,这个引用变量就不可能再改变成为其他引用实体的别名 //c = b的正确理解应该是:赋值 //将b的值赋给了c,同时c作为a的别名也改变了a,a发生改变后d作为a的别名也发生改变
三.常数引用,类型不同如何引用
结论:权限只能缩小,不能放大(以下,进一步理解这句结论)
对常变量的引用:
const int c = 10; //int& d = c;//权限不可放大,报错 const int& e = c;//正确写法 int a = 20; const int& b = a;//权限可以缩小,正确
对常量的引用:
const int& a = 10;
const int类型 --- 转变为 --- int类型(经典的权限放大)从只可读不可写 ---转变为--- 既可读又可写
int类型 --- 转变为 --- const int类型(经典的权限缩小)从既可读又可写 ---转变为--- 只可读不可写
根据这个观念,就可以来讨论一下,类型不同可以引用吗?如何引用?
在这里补充说明一下隐式类型转换的问题
int m = 1;
double n = (double)m; 这是强制类型转换
double n = m; 这是隐式类型转换
以上两种方式的意义是完全相同的
类型不同,如何引用:
int m = 10; double& n = m;//这样写会报错 const double& n = m;//这样写是正确的
n作为m的别名,他们用的是同一块空间吗?
答案:不再使用同一块空间,n与m产生的临时变量使用同一块空间,并且需要const提供常性,防止被销毁。
很清晰可以看到,a和m的地址相同,n有自己的地址; 并且所占内存字节a和m相同为4,n为double类型为8.
四.引用作为函数参数
void func(int& a, int& b){};
1.引用作为函数参数,表面上看似传值,实则传的是地址。
2.传引用的效率比传值高很多
五.引用作为函数返回值
int& func(int a, int b){};
与指针类似,指针作为返回值的需要注意,不可返回临时变量的地址,因为临时变量出函数作用域就会被销毁,指针变为野指针。
引用作为函数返回值同理,不可返回临时变量的引用,函数创建会建立函数栈帧,函数结束后,函数栈帧被系统回收,临时变量则会被销毁
(注意计算机中,没有真正意义的销毁,销毁指的就是将要销毁的空间置为无效,等待其他有效空间的创建来覆盖改空间)
所以临时变量被覆盖时,传回的引用变量就是一个不确定的随机值了
return关键字的本质就是将要返回的东西拷贝一份放到寄存器,而在语法层次来看引用没有发生拷贝直接返回的原来的东西。所以引用返回效率比返回值返回效率要高!
(但在底层实现的角度,引用是由指针实现的,所以实际就与指针类似,拷贝了地址,所以效率高)
六.引用与指针的区别
1.引用在定义时必须初始化,指针没有要求
2.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
3.没有NULL引用,但有NULL指针
4.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
5.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6.有多级指针,但是没有多级引用
7.访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8.引用比指针使用起来相对更安全



