引用的概念
初步理解:引用相当于给变量取了一个别名,它和引用的变量共用同一块空间。
就好比孙悟空有很多外号,例如孙行者,齐天大圣,斗战胜佛,但是它们所指都是孙悟空。同样的,如果齐天大圣大闹天宫,那么孙悟空也大闹天宫,所以引用改变了,相应的变量的值也改变了
int main()
{
int a = 0;
int& n = a;
n = 10;
cout << n << endl;//输出10
return 0;
}
引用的特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦有一个实体就不能有其他实体
int main()
{
int tmp = 10;
int a = 0;
int& n = a;
n = tmp;//将tmp的值赋给n引用的变量
int& x = a;
cout << x << endl << n << endl;//都是10
return 0;
}
常引用
const int a = 10;
//int& ra = a; //权限不能扩大,a有常属性,引用也要有常属性
const int& ra = a;
int tmp = a; //这是赋值,不会报错
//int& rb = 10; //权限不能扩大,10是常量,引用要有常属性
const int& rb = 10;
double d = 1.5;
//int& rd = d;
//d是double类型,与rd引用的类型不同,在被引用时,会先放到一个有常属性的临时变量里截断,再被rd引用
const int& rd = d;
double& rrd = d;
使用场景
-
作函数参数
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int e1 = 1;
int e2 = 10;
cout << "交换前:" << "e1=" << e1 << " e2=" << e2 << endl;
Swap(e1, e2);
cout << "交换后:" << "e1=" << e1 << " e2=" << e2 << endl;
return 0;
}
引用作参数可以改变实参的值,与C语言中的指针效果相同
引用做参数还可以提高效率,遇到空间较大的变量不需要拷贝
-
作函数返回值
int& fun1(int n = 0)
{
static int a = n;
a++;
return a;
}
int fun2(int n = 0)
{
int a = n;
a++;
return a;
}
int main()
{
int n = fun1(11);
cout << n << endl;
n = fun2(11);
cout << n << endl;
return 0;
}
引用作函数返回值时,要保证函数调用结束栈帧销毁后,返回的变量不被释放,例如使用静态变量
引用作函数返回值,可以提高效率。fun2函数返回a时,由于函数栈帧被销毁,会先将a的值传给一个临时变量,再将临时变量传给n,这会涉及两次变量的拷贝。fun1函数返回引用就不会拷贝。
引用的底层逻辑就是指针
引用的底层使用了指针,看下面这段代码:
int main()
{
int a = 0;
int& qa = a;
qa = 10;
int* pa = &a;
*pa = 10;
}
汇编代码:
引用和指针的区别
- 引用必须初始化,指针不用
- 引用初始化引用一个实体后不能成为其他实体的引用,而指针可以指向不同的实体
- 没有NULL引用,但是由有NULL指针
- sizeof()的结果不同,引用会返回引用类型的大小,指针会返回指针变量的大小(4/8)
- 引用自加就是变量的值+1,指针是向后偏移一个类型的大小
- 有多级指针但是没有多级引用
- 访问实体时,指针需要解引用,引用可以直接显示使用
- 引用使用更安全