C++引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活的使用引用,可以是程序简洁、高效。
引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。
一.引用(取别名,就和自己有大名和小名,外号一样)
引用的声明格式:
类型标识符&引用名=目标变量名;
int a;
int & ra=a;
注意:
1.&在此不是求地址运算,而是起标识作用。
2.声明引用必须初始化.
3.一个变量可有多个引用
4.引用一旦引用一个实体,就无法引用其它实体.不能再把该引用名作为其他变量名的别名,这样会改变原目标变量的值(原被引用变量)。
int a=10;
int & b=a;
int x=20;
b=x;//注意这里不会使b作为x的变量,而是把b的值改为x的值。现在a,b的值都为20。
5.声明一个引用,不是新定义了一个变量,因此引用本身不占用存储单元,系统也不给引用分配储存单元。故:对引用取地址,就是对目标变量求地址。&a与&ra相等。
注意:不能进行权限的放大(只适用于引用和指针间,不适用其他变量)
引用(不能放大权限)
指针(不能放大权限)
整形变量(不涉及权限)
!!!注意:隐式类型转换的引用
首先double 转换成int ,精度会降低,上述代码int f=d;从语法上8字节的double不能直接转换成4字节的int,没法直接截取,实际上,8字节的double的整数部分给了一个4字节的临时变量,临时变量再给4字节的int。(这其实很好解释了隐式转换后原有类型和值不变,是用临时变量来过渡的)
人 张三 =(人)金毛;问:狗是狗还是人?答案:狗还是狗。
同理,在引用中,int &e=d;临时变量默认被const 修饰不能传给可读可写的e(这里是权限的放大),所以改成const int&e=d;才不会报错。(我的其他博客有介绍临时变量的常性)
二.常引用
常引用声明一般形式:
const 类型标识符&引用名=目标变量名;
const int & ra=a;
这种方式声明的引用,不能通过引用对目标变量的值进行修改。
三.引用的应用
1.引用做参数
两种形式:输入型参数、输出型参数
int func(const int & a , int & p)
{
p = a +10;
}
a是输入型参数。p是输出型参数。使用输入型参数时,一般会加入const关键字,表明是只读,不能修改。
函数以引用作为形参时:不可以接受常量作为实参传递;
函数以常引用作为形参时: 可以接受常量或变量作为实参传递,但是无法通过引用对目标变量的值进行修改。
所以在设计函数时,输入性参数形参尽可能地使用 const,这样可以使代码更为健壮,将错误暴露于编译阶段。
形参为实参的引用,形参不开辟空间,比写成指针形式可读性要强。提高效率(程序的效率)
下图显示传引用作为参数的运行时间更短,效率更高。
2.引用做返回值
同样提高代码效率
但要注意!!!如果返回变量是一个局部变量,直接引用是不安全的
下列代码结果为什么是7???
原因是在第一次调用时,在栈里创建a,b,c 在这里返回c的引用 ret,这是第一次调用,返回时栈征被销毁,空间还在,但空间的使用权发生变化。
在第二次调用时,建立同样大小的栈征,ret 还是原来c的空间的引用,所以ret 就变为7。
说明如果返回变量c是一个局部变量时,引用返回是不安全的。
如果这时候随便调用其他函数,就会出现乱码,如下图。
那么如何解决???
加一个static,改变c的空间位置,c在静态区(数据段),改变c 的生命周期。
总结:如果返回变量是一个局部变量时,返回引用是不安全的,(函数销毁后,空间还在,但空间的使用权不是自己,可能会随机覆盖,出现乱码)出了作用域不在,就不能用引用作为返回值。总结:一个函数要使用引用返回,返回变量出了这个函数的作用域,还存在,就可以使用引用返回,否则就不安全。全局变量,静态变量可以使用。
四.引用和指针的实现
语法方面
引用就是a别名,不开辟空间。
地址是地址变量,开辟空间,用来储存被指向变量的地址。
但是:引用和指针在语法上是不一样的,但是实际上从反汇编的代码上我们能看到引用和指针的底层实现是一样的!
语法角度:ra是a的别名,没有额外的开辟空间。
底层角度:引用和指针是一样的方式实现的。(代码和汇编如下)
语法角度:pa存储a的地址,pa开了4/8byte空间
底层的角度:引用和指针是一样的方式实现的。(代码和汇编如下)
下图同样也是
五.引用和指针的不同
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
- 引用在定义是必须初始化,指针没有要求。
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
- 没有NULL引用,但有NULL指针。
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)。
- 引用自加即引用的实体加1,指针自加即指针向后偏移一个类型的大小。
- 有多级指针,但是没有多级引用。
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。
- 引用比指针使用起来相对安全。
谢谢您!!!看完了这篇文章,有什么错误或者问题,欢迎随时私信我或者留言。
少年没有乌托邦,心向远方自明朗!