三、引用🛫
3.1🚝 什么是引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
引用即别名:引用并非对象,相反的,它只是为一个已经存在的 对象所起的另外一个名字
语法:类型& 引用变量名(对象名) = 引用实体
📘例如:
int a = 10; int& b = a;
通过调试观察引用跟原来变量的关系↓
➡印证了概念中所说的:编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
3.2 🚝引用的定义
允许在一条语句中定义多个引用,其中每个引用标识符都必须以& 开头
int main() { int i = 1024, i2 = 2048;//i和j都是int int& r = i, r2 = i2;//r是引用,与i绑定;r2是int int i3 = 1024, &ri = i3;//i3是int;ri是引用,与i3绑定 int& r3 = i3, & r4 = i2;//r3\r4都是引用 return 0; }
3.3🚝 特性
a. 在定义时必须初始化
一般在初始化变量的时候,初始值会被拷贝到新建的对象中。But,定义引用时,程序把引用和它的初始值绑定在一起, 而不是将初始值拷贝给引用。
👉👉👉因此,一旦初始化完成,引用就跟它的初始值对象一直绑定在一起,以后就再也分不开了(即无法让这个引用绑定另一个对象了~),故引用必须初始化!
b. 引用类型的初始值必须是一个对象(不能是常量)
除了两种例外情况,其他所有引用的类型都要和与之绑定的对象严格匹配。What’s more,引用只能绑定在对象上 ,不能与字面值 or 某个表达式的计算结果绑定在一起
c. 一个变量可以有多个引用
通俗一点来说,别名可以不只有一个。
就好比孙悟空的别名有孙行者、心猿、金公、斗战胜佛、齐天大圣等等
对别名取别名也是允许的,例子见《4.1 什么是引用》的第一张图
d. 一旦引用一个实体,再不能引用其他实体
b = x就只是赋值而已,b绑定的仍是a(并不是让 b 变成 x 的别名)
3.4🚝 常引用
a. const 修饰的常变量
const int a = 10; int& ra = a; const int& cra = a;//正确
加了const限定,使得 a 不能被修改(权限为“ 只读 ”),那么a的引用也不可以被修改。a 权限是只读,但是引用 ra 没有加const修饰,权限为“ 可读可写 ”(a的引用权限放大了,会报错)
所以可以使ra的权限变成和 a 相同的,即加上 const 修饰 ra (见上图),就可以消除这个error了
b. 常量
int& b = 10; // 该语句编译时会出错,b为常量 const int& rb = 10;//正确
解释跟a. const 修饰的常变量类似
c. 不同类型
double d = 12.34; int& rd = d; // 该语句编译时会出错,类型不同 const int& rd = d;//会给出警告,但不是error
double变int会丢失精度
3.5🚝 引用与指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
这里我们不需要理解引用底层的实现(引用的底层其实也是用指针实现的)
只明确引用不开辟空间就行了
引用和指针的不同点:
引用概念上定义一个变量的别名,指针存储一个变量地址。
引用在定义时必须初始化,指针没有要求
引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
没有NULL引用,但有NULL指针
在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
有多级指针,但是没有多级引用
访问实体方式不同,指针需要显式解引用,引用编译器自己处理
引用比指针使用起来相对更安全