引用
1.概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编不会为引用变量开辟内存空间,它和它引用的变量公用一块内存空间
例1
比如说 李逵,在家称为"铁牛", 江湖上人称"黑旋风" 这两个称号都是他的
例二
#include<iostream>
using namespace std;
int main()
{
int a = 20;
int& b = a;
b = 20;
return 0;
}
b是a的引用,也就是起了一个别名,a再取了一个名称
同时改变别名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.引用一旦引用一个实体,再不能引用其他实体
此时由于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.权限问题
别名d 的权限从原来c的可读可写变成了只读,所以可以通过
总结:引用取别名时,变量访问权限可以缩小不能放大
4.引用误区
赋值与起别名是两回事
1.起别名
#include<iostream>
using namespace std;
int main()
{
const int a = 1;
int& b = a;
return 0;
}
由于起别名是给自己再取一个名称,所以该别名的修改会影响到本身变量 所以就要求 别名的权限可以小于等于本身变量,但不能大于本身变量
2.赋值
#include<iostream>
using namespace std;
int main()
{
const int a = 1;
int b = a;
return 0;
}
赋值不会改变a变量本身,自然就不用考虑权限大小的问题
5.使用场景
1.引用做参数
相当于 int &s1=a; int &s2=b; s1是a的别名,s2是b的别名
2.引用做返回值
为什么 r1不可以接收,而r2可以呢?
1.传值返回
在count1中返回的实际上是一个临时变量 假设临时变量为tmp,开辟了一块空间 即 int tmp=n 即tmp为n的拷贝
2.传引用返回
在count2中,假设有一个临时变量tmp,但是该变量没有开辟空间, 因为tmp是作为n的别名,即tmp为n本身 int& tmp=n
3.解释
在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
c是局部变量,所以会随着函数的销毁而销毁,因为是引用返回,ret为c的别名 ret=3
再次创建跟跟刚才同样大小的空间,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
c此时处于静态区中,所以不会随着函数的销毁而销毁 引用返回,ret为c的别名,ret=3
因为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;
效率差距还是有的,引用返回,不需要创建空间来存储临时变量, 而值返回则需要创建空间来存储临时变量