C++之引用

一.引用概念

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它 引用的变量共用同一块内存空间。
类型 & 引用变量名 ( 对象名 ) = 引用实体,比如:
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.引用做参数

引用的价值
做参数 --  a、提高效率 b、形参的修改,可以影响实参(输出型参数)

// 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;
}

引用作返回值有两大优势,一个是前面说的提高效率,还有一个就是可以修改返回变量,如下所示

int& At(int i)
{
	static int a[N];
	return a[i]; // 返回的是a[i]数组的别名
}

int main()
{
	int ret = Add(1, 2);

	for (size_t i = 0; i < N; ++i)
	{
		At(i) = 10+i;
	}

	for (size_t i = 0; i < N; ++i)
	{
		cout << At(i) << " ";
	}
	cout << endl;

	return 0;
}

总结一下:

引用的作用主要体现在传参和传返回值
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;
}

六.引用和指针的区别

1. 引用 在定义时 必须初始化 ,指针没有要求
2. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型
实体
3. 没有 NULL 引用 ,但有 NULL 指针
4. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32 位平台下占
4 个字节 )
5. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全,指针要考虑空指针,野指针等等问题,指针太灵活了,所以相对而言,没有引用安全

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值