目录
1. 引⽤的概念和定义
2. 引⽤的特性
3. 引⽤的使⽤
4. const引⽤
5. 指针和引⽤的关系
1. 引⽤的概念和定义
引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名(相当于是给变量起了个外号),编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋⻛";林冲,外号豹⼦头;
类型& 引⽤别名 = 引⽤对象;
这⾥引⽤也和取地址使⽤了同⼀个符号&,⼤家注意使⽤⽅法⻆度区分就可以。
#include<iostream>
using namespace std;
int main()
{
int a = 0;
// 引⽤:b和c是a的别名
int& b = a;
int& c = a;
// 也可以给别名b取别名,d相当于还是a的别名
int& d = b;
++d;
// 这⾥取地址我们看到是⼀样的
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;
return 0;
}
运行结果:
可见a,b,c,d的地址打印出来是一样的。
2. 引⽤的特性
•
引⽤在定义时必须初始化
•
⼀个变量可以有多个引⽤
•
引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体,不能改变引用的指向。
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int& b = a;
int c = 20;
// 这⾥并⾮让b引⽤c,因为C++引⽤不能改变指向,
// 这⾥是⼀个赋值
b = c;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
return 0;
}
结果是a与b的地址是一样的,且与c不同。
3. 引⽤的使⽤
•
引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象。
•
引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。
•
引⽤返回值的场景相对⽐较复杂,我们在这⾥不展开介绍。
•
引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向, Java的引⽤可以改变指向。
•
⼀些主要⽤C代码实现版本数据结构教材中,使⽤C++引⽤替代指针传参,⽬的是简化程序,避开复杂的指针,但对于没有学过c++的同学来说是雪上加霜了。
4. const引⽤
•
可以引⽤⼀个const对象,但是必须⽤const引⽤。const引⽤也可以引⽤普通对象,因为对象的访
问权限在引⽤过程中可以缩⼩,但是不能放⼤。
•
不需要注意的是类似
int& rb = a*3; double d = 12.34; int& rd = d;
这样⼀些场景下a*3的和结果保存在⼀个临时对象中, int& rd = d
也是类似,在类型转换中会产⽣临时对象存储中间值,也就是时,rb和rd引⽤的都是临时对象,⽽C++规定临时对象具有常性,所以这⾥就触发了权限放⼤,必须要⽤常引⽤才可以。
•
所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,
C++中把这个未命名对象叫做临时对象。
#include<iostream>
using namespace std;
int main()
{
int a = 10;//可读可写
const int& ra = a;//可读不可写,权限缩小
return 0;
}
#include<iostream>
using namespace std;
int main()
{
const int a = 10;//可读不可写
int& ra = a;//可读可写,权限放大,报错
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int a = 1;
int b = 1;
const int& c = 10;//常量只能用const来修饰,不可更改
const int& d = a + b;//在这里d只能用const来修饰,因为a+b后会产生临时变量,
//临时变量具有常属性,也相当于常量
return 0;
}
#include<iostream>
using namespace std;
int main()
{
double a = 0.1;
int& b = a;//会报错
return 0;
}
但是用const来修饰就是对的
#include<iostream>
using namespace std;
int main()
{
double a = 0.1;
const int& b = a;//正确
return 0;
}
在这里a会发生隐式类型转换,从double类型转换为int类型,中间会将转换后的数据存在临时变量中(具有常性),因此要用const来修饰。
5. 指针和引⽤的关系
C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有⾃⼰的特点,互相不可替代。
•
语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
•
引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
•
引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
•
引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
•
sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)
•
指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。
#include<iostream>
using namespace std;
int main()
{
int* ptr = NULL;
int& rptr = *ptr;
return 0;
}
上面的代码看着很奇怪,但是我们只要理解了引用的底层是指针就迎刃而解了,这其实就是指针之间的赋值,但是我们平时就是认为引用没有开辟空间,就是起别名。
下面就是可能产生野引用的情况,在调用func函数结束后栈帧被销毁,p就是野引用了。
#include<iostream>
using namespace std;
int& func()
{
int a = 10;
return a;
}
int main()
{
int& p = func();
return 0;
}
****************************************感谢观看,欢迎评论区指正************************************