一.引用概念
引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它 引用的变量共用同一块内存空间。
类型 & 引用变量名 ( 对象名 ) = 引用实体,比如:
int main()
{
int a = 10;
int& b = a;//引用取别名,定义引用类型
int* p = &b;//取地址
}
二.引用需要注意的问题
1.引用在定义时必须初始化
//1.引用在定义时必须初始化
int a = 10;
int& b = a;
2.一个变量可以有多个引用
//2.一个变量可以有多个引用
int a = 10;
int& b = a;
int& c = a;
int& d = b;
3.引用一旦引用一个实体,再不能引用其他实体,与指针区分开
三.引用的应用
1.引用做参数
// 1、引用做参数(总结有三种传参方式)
// _Z4swappipi
void swap(int* p1, int* p2) // 传地址
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
// _Z4swapriri
void swap(int& r1, int& r2) // 传引用
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
// _Z4swapii
void swap(int r1, int r2) // 传值
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
// 他们三个构成函数重载
// 但是swap(x, y);调用时存在歧义,他不知道调用,传值还是传引用
// 类似以前讲的这个,他们构成重载,但是存在歧义
// void f();
// void f(int x = 0, int y = 0);
2.指针的引用
3.引用作返回值
先说传值返回,传值返回,会产生一个临时变量。然后将返回值拷贝给临时变量,再将临时变量拷贝给调用函数。
再说传引用返回,引用返回的意思就是不会生成c的拷贝返回,直接返回c的引用
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。比如
在下面这个程序中,使用引用返回,会有非常大的优势
#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回 -- 每次拷贝40000byte
A TestFunc1() { return a; }
// 引用返回 -- 没有拷贝
A& TestFunc2(){ return a; }
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
总结一下:
引用的作用主要体现在传参和传返回值
1、引用传参和传返回值,有些场景下面,可以提高性能。(大对象+深拷贝对象)
2、引用传参和传返回值,输出型参数和输出型返回值。通俗点说,有些场景下面,形参的改变可以改变实参。有些场景下面,引用返回,可以改变返回对象。
四.常引用
// 假设x是一个大对象或者是后面学习深拷贝的对象
// 那么尽量用引用传参,减少拷贝。如果f函数中不改变x
// 建议尽量用cosnt引用传参,因为传过来的值相当于权限缩小了
//void f(int& x)
void f(const int& x)
{
cout << x << endl;
}
// 常引用
int main()
{
// 权限放大 不可以
//const int a = 10;
//int& b = a;
// 权限不变 可以
const int a = 10;
const int& b = a;
// 权限的缩小 可以
int c = 10;
const int& d = c;
f(a);
f(c);
f(10);
return 0;
}