引用

1.概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编不会为引用变量开辟内存空间,它和它引用的变量公用一块内存空间

例1

比如说 李逵,在家称为"铁牛", 江湖上人称"黑旋风" 这两个称号都是他的 image.png

例二

#include<iostream>
using namespace std;
int main()
{
	int a = 20;
	int& b = a;
	b = 20;
	return 0;
}

b是a的引用,也就是起了一个别名,a再取了一个名称

image.png

同时改变别名b的值,也会改变a本身的值

2.特性

1.引用必须在定义时初始化

1.错误举例
#include<iostream>
using namespace std;
int main()
{
	int a = 20;
	int& b;
	return 0;
}

若使用引用不初始化,b是谁的别名?

2.一个变量可以有多个别名

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	int& d = a;
	return 0;
}


3.引用一旦引用一个实体,再不能引用其他实体

image.png

此时由于b与c的地址不同,说明并不是b作为c的别名 b值与c值相等,而是将c的值传给b

3.常引用

1.错误举例

#include<iostream>
using namespace std;
int main()
{
	const int a = 10;
	int& b = a;
	return 0;
}

const 修饰a后,a为只读,b是int型,所以为可读可写。 所以会报错

2.正确举例

#include<iostream>
using namespace std;
int main()
{
	const int a = 10;
	const int& b = a;
	return 0;
}

将b的类型修改为const int型 即可通过

3.权限问题

image.png

别名d 的权限从原来c的可读可写变成了只读,所以可以通过

总结:引用取别名时,变量访问权限可以缩小不能放大

4.引用误区

赋值与起别名是两回事

1.起别名

#include<iostream>
using namespace std;
int main()
{
	const int a = 1;
	 int& b = a;
	return 0;
}

image.png

由于起别名是给自己再取一个名称,所以该别名的修改会影响到本身变量 所以就要求 别名的权限可以小于等于本身变量,但不能大于本身变量

2.赋值

#include<iostream>
using namespace std;
int main()
{
	const int a = 1;
	 int  b = a;
	return 0;
}

image.png

赋值不会改变a变量本身,自然就不用考虑权限大小的问题

5.使用场景

1.引用做参数

image.png

相当于 int &s1=a; int &s2=b; s1是a的别名,s2是b的别名

2.引用做返回值

image.png

为什么 r1不可以接收,而r2可以呢?

1.传值返回

image.png

在count1中返回的实际上是一个临时变量 假设临时变量为tmp,开辟了一块空间 即 int tmp=n 即tmp为n的拷贝

2.传引用返回

image.png

在count2中,假设有一个临时变量tmp,但是该变量没有开辟空间, 因为tmp是作为n的别名,即tmp为n本身 int& tmp=n

3.解释

image.png

在r1接收返回时,因为count1返回临时变量tmp具有常性,所以r1要用 const修饰 在r2接收返回时,因为返回的临时变量tmp为n本身,n为int型,所以可以正常返回

6.使用局部变量返回的危害

#include<iostream>
using namespace std; 
 int& add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = add(1, 2);
	add(3, 4);
	cout << ret << " " << endl;	
	return 0;
}

该程序执行完,结果是什么? 正常来说,ret=3,实际结果ret=7

image.png

c是局部变量,所以会随着函数的销毁而销毁,因为是引用返回,ret为c的别名 ret=3

image.png

再次创建跟跟刚才同样大小的空间,c的值变化为7,由于ret为c的别名,所以ret=7

###1.解决方法

使用static引用返回

#include<iostream>
using namespace std; 
 int& add(int a, int b)
{
	static int c = a + b;
	return c;
}
int main()
{
	int& ret = add(1, 2);
	add(3, 4);
	cout << ret << " " << endl;	
	return 0;
}

ret=3 image.png

c此时处于静态区中,所以不会随着函数的销毁而销毁 引用返回,ret为c的别名,ret=3

image.png

因为static int c=a+b,只会定义一次 add(3,4) 中c值依旧为3 所以ret=3

2.测试用例

#include<iostream>
#include<time.h>
using namespace std;
struct A
{
int a[10000];
};
A a;
A test1()//值返回
{
return a;
}
A& test2()//引用返回
{
return a;
}
int main()
{
//以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 1000000; i++)
{
test1();
}
size_t end1 = clock();
//以引用返回作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 1000000; i++)
{
test2();
}
size_t end2 = clock();
//计算两个函数运算完成之后的时间
cout << "test1 time :" << end1 - begin1 << endl;
cout << "test2 time :" << end2 - begin2 << endl;

return 0;


image.png

效率差距还是有的,引用返回,不需要创建空间来存储临时变量, 而值返回则需要创建空间来存储临时变量