本文将讲述,C++中的引用&
作者:迷茫的启明星
欢迎关注:点赞收藏✍留言
家人们,码字不易,你的点赞收藏关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!
持续更新中~
引用&
引用的概念
引用并不是定义一个新的变量,而是给已经存在的变量取一个别名,相当于外号,编译器不会给它开辟内存空间,它和它所引用的变量共用一块空间。
比如说:宋江,江湖人称“及时雨”,本质都是宋江,不过是一个外号
引用的格式:
类型&引用变量名=引用实体;
voidtest1
{
inta=1;
int&b=a;//定义引用的类型
cout<<><>< p=''><><><><>
cout<<><>< p=''><><><><>
}
```
这里要注意的是,引用的类型必须和引用的实体是同种类型的。
引用的特性
引用在定义的时候必须初始化
也就是说它引用的是已经存在的变量(空间)
一个变量可以有多个引用
也就是说给一个实体取多个“外号”
引用一旦引用一个实体,就不能再引用其他的实体了
也就是说不能再把这个“外号”给别人了
voidtest2{inta=1;intx=2;//int&b;//这个引用没有初始化,编译会报错int&b=a;int&c=a;//多个引用(多个外号)//int&c=b//引用多个实体,不同实体有相同的外号,会报错}
常引用
intmain{//权限放大不可以constinta=10;int&b=a;//权限不变可以constinta=10;constint&b=a;//权限的缩小可以intc=10;constint&d=c;return0;}
在引用时要注意,只能把自己有的给别人,自己都没有权限怎么给呢?
引用的应用
在之前我们实现链表是使用指针来做参数的,现在我们就可以利用引用的性质来实现它。
譬如:实现尾插
之前使用指针是这样的(仅展现部分代码,理解就好)
voidSListPushBack(SLTNode**pphead,SLTDateTypex){SLTNode*newnode=BuyListNode(x);if(*pphead==NULL){*pphead=newnode;}else{//找到尾节点SLTNode*tail=*pphead;while(tail->next!=NULL){tail=tail->next;}tail->next=newnode;}}intmain{SLTNode*plist=NULL;SListPushBack(&plist,1);SListPushBack(&plist,2);SListPushBack(&plist,3);SListPushBack(&plist,4);return0;}
现在我们就可以这样写
voidSListPushBack(SLTNode*&pphead,SLTDateTypex){SLTNode*newnode=BuyListNode(x);if(pphead==NULL){pphead=newnode;}else{//找到尾节点SLTNode*tail=pphead;while(tail->next!=NULL){tail=tail->next;}tail->next=newnode;}}intmain{SLTNode*plist=NULL;SListPushBack(plist,1);SListPushBack(plist,2);SListPushBack(plist,3);SListPushBack(plist,4);return0;}
pphead是plist的别名,改变pphead就是改变plist
做参数
使用引用的好处就在于,没有指针那么复杂,还要使用二级指针,难以理解。再就是,定义函数时,要么就是传值,要么就是传址,现在就有了第三种情况传引用。
voidswap(intr1,intr2)//传值{inttmp=r1;r1=r2;r2=tmp;}
voidswap(int*p1,int*p2)//传地址
{
inttmp=*p1;
*p1=*p2;
*p2=tmp;
}
voidswap(int&r1,int&r2)//传引用
{
inttmp=r1;
r1=r2;
r2=tmp;
}
引用又有了另一个好处
它不需要开辟新的空间,是在原空间操作,这在数量级小的时候不起眼,可是在递归时就显得尤为可贵了,虽说传地址所需空间也少,但是在有时候,还是不如&方便。
#include
点击加载图片
这里还要注意一个点,如果使用引用传参,函数中不改变参数的值,建议使用const&
做返回值
#include
点击加载图片
使用引用作返回值时,看上去是不是觉得效率提升了很多?但是这里有个大坑,虽说传值返回会生成拷贝,但是它在结束时会产生一个临时变量,临时变量再给调用的地方,至少是安全的
这里提一下临时变量存在哪里
如果比较小(4/8),一般是存在寄存器中
如果比较大,就会放在调用函数的栈帧中
接前面继续讲
引用做返回值,它引用的是什么呢?
是返回值,但是我们要知道,函数结束后,栈帧就销毁了,
它这个时候就相当于非法访问了,它访问的就可能是随机值(编译器不同而不同),
那么我们应该怎么使用它呢?
需要记住这个规则:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
比如:
int&count
{
staticintn;//静态
n++;
retuernn;
}
它就可以使用引用作返回值
引用和指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
intmain{inta=10;int&ra=a;cout<<'&a='<<&a<<><>< p=''><><><><>
但是,在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
intmain{inta=10;int&ra=a;ra=20;int*pa=&a;*pa=20;return0;}
我们来看下引用和指针的汇编代码对比
点击加载图片
引用和指针的不同点:
引用概念上定义一个变量的别名,指针存储一个变量地址。
引用在定义时必须初始化,指针不是必须
引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
没有NULL引用,但有NULL指针
在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
有多级指针,但是没有多级引用
访问实体方式不同,指针需要显式解引用,引用编译器自己处理
引用比指针使用起来相对更安全,因为不用像指针那样要考虑野指针、空指针等问题。
总结
本文讲述了,C++中的引用&,下一篇将讲述C++初识下篇。
respect!
下篇见!
联系客服