文章目录
- 前言
- 一、引用
- 1.1 理解引用
- 1.2 引用的特性
- 1.3 引用的权限
- 1.4 引用的使用场景
- 1.4.1 做参数
- 1.4.2 做返回值
- 1.5 引用的本质
前言
C语言中什么最难学?那当然就是指针了。不但使用起来麻烦,时不时还会产生一些意料之外的错误。C++提供了一种方式,能做到指针的作用,但比指针用起来更容易。这种方式称为引用。
一、引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。我们叫铁牛,黑旋风都是指李逵。
1.1 理解引用
首先我们看看如何使用引用:
类型& 引用变量名(对象名) = 引用实体
引用不是新定义一个变量,而是给已存在变量取了一个别名
看了这个例子,我想你应该能深刻理解这句话了。
不难看出,引用比指针方便了不少。不用麻烦的去写取地址,解引用。
1.2 引用的特性
虽然引用很好用,但使用方式不对,那也没用。
-
引用必须初始化
-
一个实体可以有多个引用,但一个引用只能指向一个实体,且不能改变。
当然不是,c = b;是将b的值赋给c,而c又是a的引用(别名),即将b的值赋给a
-
引用的对象可以是变量、常量……,使用时注意引用类型必须和引用实体是同种类型
(这里会涉及到引用的权限,后文有讲)
1.3 引用的权限
上面提到引用的对象可以是常量,那可以写出这样的代码
int& a = 10;
但很遗憾,这样写是错的。const int& a = 10;
这样写才对。
要搞明白为什么,需要我们知晓引用的权限。
首先,我们要了解权限是什么?看下面代码
int a = 10;
int& b = a;
b能改变a吗?当然可以,b = 11;
a就变为11,此时的b相当于我们使用电脑时,以管理员的方式运行,权限很大。它可以读写a,影响到a。这就是引用b的权限。
回到上面的问题,为什么必须写成const int& a = 10;
?因为10是常量,常量不能改变。如果写成int& a = 10
,这不就和刚才的b一样吗,表式a有能力改变10,但10是常量,不能改变。因此我们不能给a能够改变10的权限,即a只能读,不能写,所以我们需要加上const
。
了解权限是什么,下面我们来学习如何正确给与权限。
引用过程,权限不能增大,只能平移或缩小。
有两种特殊情况,如下
- 类型转换时,权限变化
在发生类型转换时,会产生临时变量,临时变量具有常性(相当于加了const), 如下
同理,const int& c = a;
c是临时变量的引用,权限为只读。
小知识:c为临时变量的引用,那临时变量用完销毁后,c会这么办?答案是临时变量不会立马销毁,
对于类似于int& c = a;这样的引用初始化,编译器会将其实现为一个指针,并在需要时进行隐式解引用。所以,即使原始对象离开了作用域,只要其引用仍然存在,临时变量也会与引用一起存在,直到引用失效。换句话说,临时变量的生命周期是由其所绑定的引用决定的,而不是由其作用域决定的。
函数返回值,放回值会放在临时变量里,临时变量具有常性。
既然函数返回值也是通过临时变量来传递的,那如果用引用接收该怎么写?
如下:
1.4 引用的使用场景
1.4.1 做参数
- 输出型参数
我们在力扣上使用c语言刷题时,常常出现这么一个参数int* returnSize
,这里的returnSize就是输出型参数。即能够将值带回的参数。
- 提高效率
函数传值调用:函数形参是函数实参的临时拷贝,如果函数实参过大,形参也就很大。所以实参过大时,一般都是传址调用。引用相当于传址调用,因此能节省效率。
1.4.2 做返回值
上面提到函数返回值会被放在临时变量里。那如果返回的对象数据量很大呢?那么临时变量就会很大,这就很低效了。那我们怎么做?返回它的引用。
当函数的返回引用时,不会创建临时变量。
因此返回引用能够提高效率——吗?
之前我们提到,如果临时变量用引用来接收,会延长临时变量的作用域,所以引用能指向正确的空间(临时变量的地址)。但现在函数返回引用是不会创建临时变量,那引用指向哪块空间呢?
问题来了,如下:
但为什么打印的结果会是19呢?而且并没有报错。
因此这取决于编译器,我使用的是VS2022。根据结果可以推断,VS2022并没有清理函数栈帧,也没有禁止这种非法访问。
因此这样使用引用,不但不能提高效率,反倒有很大可能出现bug。
那用引用做返回值岂不是没什么用?
返回全局变量、静态变量、堆区上的空间的引用就可以了。
这些空间不会在函数调用结束后释放。
1.5 引用的本质
其实引用就是通过指针来实现。我们说引用不开辟空间,是从语法层面来说的,从底层来看,引用就是指针,会开辟空间。
因此,在C++中,我们可以将引用视为一种语法上的简洁方式来处理指针的语义。