C++——引用

玛丽亚后 2024-06-15 14:05:02 阅读 71

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

前言

一.引用

1.1引用概念

1.2引用特性

1.3使用场景

1.4常引用

1.5 指针与引用的区别


 

8fb442646f144d8daecdd2b61ec78ecd.png

前言

本篇文章主要讲述在C++中关于引用的一些概念及其用法,还有引用与指针的些许区别,希望能够帮助大家理解~

一.引用

1.1引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,这里我们可以理解为取外号,就比如宋江外号叫及时雨,它们二者都是指向同一个人——引用的变量也是与原变量共享一块内存空间。

类型& 引用变量名(对象名) = 引用实体;

#include <iostream>using namespace std;int main(){int a = 1;int b = a;int& ra = a;printf("%p\n", &a);printf("%p\n", &b);printf("%p\n", &ra);return 0;}

这里我们可以发现a与ra是共用一块内存空间的,而b则是另外开辟一处。

int main(){int a = 1;int b = a;int& ra = a;ra++;b--;cout << ra << endl;cout << a << endl;cout << b << endl;cout << " " << endl;a++;cout << ra << endl;cout << a << endl;cout << b << endl;return 0;}

从这里我们也可以看出ra++会影响到a的变化,而a++同样也会影响到ra。b只是a的拷贝,是完全独立的。

注意:引用类型必须和引用实体是同种类型的 

1.2引用特性

引用在定义时必须初始化

就像你给别人取外号的前提是那个人得存在,不存在是没办法取外号的。

一个变量可以有多个引用

int main(){int a = 1;int& b = a;int& c = a;printf("%p %p %p", &a, &b, &c);return 0;} 引用一旦引用一个实体,再不能引用其他实体。

这里我们可以理解为引用——称号,而每一个人可以有很多种称号,但每一个称号都是唯一的,只能对应一个人。就比如弼马温,斗战胜佛,齐天大圣等等这些称号都是指向同一个人的,具有单一性。

1.3使用场景

做参数

void Swap(int& left, int& right){int temp = left;left = right;right = temp;}int main(){int a = 1;int b = 2;Swap(a, b);cout << a << ' ' << b << endl;return 0;}

当我们的形参添加引用时Swap交换函数就发生了改变。没有引用时只是传值拷贝, 并不会真正使得外面的a与b交换。而当我们用引用来作为形参时,引用与原变量都是同一个对象,引用发生改变那么传递的变量也会发生改变。

做返回值

注意:以下用例(包含错误用例)只为引出一个结论:引用返回值不适用于在栈帧中开辟的变量。

这里的返回值并不是真正的n,它在出作用域就被销毁了,所以ret接收的只是n的拷贝。

int& Count(){int n = 0;return n;}int main(){int ret = Count();cout << ret << endl;return 0;}

该处返回的是n的别名(假设为temp),那么ret接收的可就是一个不确定值的n,因为在出Count函数作用域后对应的栈帧会销毁,而为n所开辟的空间我们不清楚是否也会跟着销毁,直接访问它会有风险。

这是一个有趣的例子,我们再通过ret作为n别名的别名。这样就意味着ret也指向n同处一块空间了,所以会有打印两次ret而出现3,7的情况,虽然在其中包含了空间重复利用的特点,但这种现象还是不可取的。

就比如ret目前充当的是n的通灵师,二者在进行灵魂的沟通,可就在休息一会(离开函数作用域再重新调用进入)后发现n突然性情大变(数据发生变化),那之前得到的信息又是否准确呢?

所以对处于栈帧中的变量使用引用返回本身就是不靠谱的事,要么可能被销毁返回一个随机值,要么中途多次调用导致数据变化,这些都是不稳定因素。

int& Count(int a, int b){static int c = a + b;return c;}int main(){int& ret = Count(1, 2);cout << ret << endl; //3Count(3, 4);cout << ret << endl; //3return 0;}

int& Count(int a, int b){static int c;c = a + b;return c;}int main(){int& ret = Count(1, 2);cout << ret << endl; //3Count(3, 4);cout << ret << endl; //7return 0;}

这里用引用返回就不会出错,因为c是在静态区所开辟的变量而非栈帧。不过为何会出现不同的值呢?因为涉及到了一个小知识点:static只会初始化一次语句(用完不会再出现)。

因此我们要想使用引用返回那就得避开栈帧,而全局,堆,静态区等都是可以引用返回的。

引用返回的真正价值

通常情况下我们对一个顺序表进行修改是如下表示:这样修改是比较别扭的

而且针对每个位置的值进行++也很麻烦,但在C++中用了引用返回就很简单了~ 

而且没有引用的话那SLat(&s,3) = 10也无法执行,因为没有引用的话是传值返回,返回的是它的拷贝,而拷贝是临时对象具有常性,是没办法修改赋值的。

1.4常引用

权限不能放大

int main(){const int a = 10;int& b = a;return 0;}

b无法引用由const所修饰的变量,就好比孙悟空齐天大圣,都是同一只猴呀,凭啥前者要戴上紧箍咒(const)而后者七十二般变化潇洒自在(变量)。

int main(){const int a = 10;const int& b = a;return 0;}

既然我们是同为一体的,那作为我的别名你也不能越界,你也要戴上紧箍咒,这就是权限平移

权限可以缩小

int main(){int a = 10;const int& b = a;return 0;}

毕竟你只是我的别名,最大上限就是我本身,那别名稍微限制点也情有可原。

另外常引用也经常出现在类型的隐式转换中。

int main(){int i = 0;double& j = i;return 0;}

上述语句是错误的,之所以如此是因为任何类型的隐式转换都不会去改变自身类型,而是生成一个转换好类型的临时变量,而临时变量具有常性,需要在前面加上const加以修饰才可引用。

总之隐式转换要想引用的时候,const是必不可少的。

1.5 指针与引用的区别

从语法上引用不需要开辟空间,而指针需要引用必须要有实体初始化,没有空引用,可以有空指针从概念上引用是对象的别名,而指针是存储变量地址从用途上引用不能任意修改指向的对象,而指针可以随意改变指向从大小上用sizeof时,引用计算的是所属类型的大小,而指针则统一是4or8字节从自增运算上引用的变量是在数值基础上自增1,而指针是跳过一个类型的大小有多级指针,无多级引用引用相对指针更安全点,使用时也不用像指针一样用*显示解引用



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。