C++ 引用

一、引用

1.1 引用是什么

 想必大家都读过四大名著之一的《水浒传》,小说中每个英雄除了有自己本身的名字以外,根据人物外表性格还有许多绰号。比如:宋江又叫:及时雨、呼保义、孝义黑三郎、宋公明、宋押司。李逵又叫铁牛、黑旋风。C++引入了引用这个概念,引用不是新定义一个变量,而是给已存在变量取了一个别名。在语法层面:编译器不会为引用变量开辟内存空间,它和引用的变量共用同一块内存空间

1.2 引用的用法

用法:引用对象类型& 别名 = 引用对象;

#include <iostream>

using namespace std;

int main()
{
	int x = 10;
	int& alias_x = x; // 引用对象x为int类型,所以引用类型也为int
	cout << "&x = " << &x << endl;
	cout << "&alias_x = " << &alias_x << endl;
	alias_x = 20;
	cout << "x= " << x << endl;
	cout << "alias_x= " << alias_x << endl;
	
	return 0;
}

输出:

&x = 009BFBBC
&alias_x = 009BFBBC
x= 20
alias_x= 20

我们可以看到xalias_x的内存地址相同,修改x就是修改alias_x,修改alias_x就是修改x

1.3 引用的特性

1.3.1 引用在定义时必须初始化

引用语法层面是某个对象的别名,所以在定义时必须初始化,不能引用一个未知的对象

int x = 10;
int& alias_x; // 错误,引用在定义时必须初始化,不能引用未知对象
int& alias_x = nullptr; // 错误,不能引用一个空对象
int& alias_x = x; // 正确 

1.3.2 一个对象可以有多个引用

水浒传中好汉可以有多个绰号,一个对象可以有多个引用

	int x = 10;
	int& alias_x1 = x;
	int& alias_x2 = x;
	int& alias_x3 = x;

1.3.3 一旦引用一个对象,再不能改为引用其他对象

引用是一个非常专一的“人”,一旦引用了某个对象,就不能在改为引用其他对象了

#include <iostream>

using namespace std;

int main()
{
	int x = 10;
	int y = 20;
	int& alias_x = x;
	cout << "&x = " << &x << endl;
	cout << "&y = " << &y << endl;
	cout << "&alias_x = " << &alias_x << endl;
	cout << "alias = " << alias_x << endl;
	alias_x = y; // 一旦引用一个对象,在不能引用其他对象,这里是将y的值赋值给alias_x,而不是引用y
	cout << "&x = " << &x << endl;
	cout << "&y = " << &y << endl;
	cout << "&alias_x = " << &alias_x << endl;
	cout << "alias = " << alias_x << endl;
	
	return 0;
}

输出

&x = 0058FA08
&y = 0058F9FC
&alias_x = 0058FA08
alias = 10
&x = 0058FA08
&y = 0058F9FC
&alias_x = 0058FA08
alias = 20

可以发现alias_x地址并未发生改变,只是alias_x值变为20

1.3.4 引用类型必须和引用对象的类型相同

在这里插入图片描述

1.4 引用的权限

#include <iostream>

int main()
{
	const int x = 10;
	//int& alias_x = x; 权限放大,编译错误,x 为常变量,而alias_x 为变量
	
	const int& alias_x = x; //权限不变可以,alias_x与y都为常变量 正确

	int y = 10;
	const int& alias_y = y; // 权限缩小,y为变量,而alias_y为常变量 正确
}

1.5 引用的本质

引用的本质就是指针,引用一个对象其实就是存储这个对象的内存地址,当要使用时编译器自动对指针解引用访问对应对象,所以使用引用会开辟内存空间存放对象地址,32位系统下占4字节,64位系统下占8字节
在这里插入图片描述

二、引用的应用场景

2.1 引用做函数形参

2.1.1 形参可以改变实参

当函数内形参的改变实参也改变时,可以用引用

void swap1(int x,int y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

void swap2(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}

void swap3(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

swap1中函数内x与y交换,函数外的实参并没有发生改变,因为形参只是实参一份临时拷贝

swap2中形参px、py存放的是实参的地址,对形参修改会改变外面的实参

swap3中使用了引用,引用的本质就是指针,等同于swap2

2.1.2 提高效率

当函数的形参变量类型很大时,直接传值调用,形参是实参的临时拷贝,效率很低。可以使用引用

#define MAXSIZE 10000 //数组大小

typedef	int ElemType; //元素类型重定义,以后元素类型发生改变只用改这里

typedef struct SeqList
{
	ElemType data[MAXSIZE];
	int length; //顺序表当前长度(已存放元素个数)
}SeqList;

void Print1(SeqList s)
{
	for (int i = 0; i < s.length; i++)
	{
		printf("%d ", s.data[i]);
	}
}

void Print2(SeqList& s)
{
	for (int i = 0; i < s.length; i++)
	{
		printf("%d ", s.data[i]);
	}
}

调用函数Print1时,需要将SeqList类型的实参拷贝给形参,而SeqList类型大小为40004字节,开销很大,效率很低

调用函数Print2时,形参本质是指针

2.2 引用做函数返回值

当函数的返回值类型很大时,直接传值返回,实际返回的是返回值的临时拷贝,效率很低。可以使用引用

#define MAXSIZE 10000 //数组大小

typedef	int ElemType; //元素类型重定义,以后元素类型发生改变只用改这里

typedef struct SeqList
{
	ElemType data[MAXSIZE];
	int length; //顺序表当前长度(已存放元素个数)
}SeqList;

SeqList s; // 全局变量

SeqList Test1()
{
	return s;
}

SeqList& Test2(SeqList& s)
{
	return s;
}

函数Test1返回时,先将返回值拷贝给临时变量,再将临时变量返回,而SeqList类型大小为40004字节,开销很大,效率很低

函数Test2返回时,返回引用,引用本质是指针,只需要将指针拷贝给临时变量,再将临时变量返回

三、引用的陷阱

引用做为函数返回值时,不要返回函数内的局部变量。局部变量出了函数作用域生命周期就结束了,虽然有的编译器不会将这部分空间清0,但是这部分空间已经不属于我们了,在尝试访问或修改这部分空间属于非法访问内存

int& Add(int x, int y)
{
	int result = x + y;
	return result;
}

int main()
{
	int& ret = Add(5, 5);
	cout << "ret = " << ret << endl;
	Add(1, 1);
	cout << "ret = " << ret << endl;

	return 0;
}

输出

ret = 10
ret = 2

add函数内的result是局部变量,出了函数作用域生命周期结束,返回result并保存在ret中已经属于非法访问内存了。测试环境中编译器并没有将这部分空间清0,所以再次调用函数后,ret值变为了2

四、引用与指针对比

4.1 相同点

引用的本质就是指针,只是编译器对引用做了封装而已
引用与指针所占空间大小一样

4.2 不同点

●引用在定义时必须初始化,指针没有要求
●一旦引用一个对象,再不能改为引用其他对象,而指针可以随时指向一个同类型对象
●不能引用NULL,但有NULL指针
● 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
● 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
● 有多级指针,但是没有多级引用
●访问对象方式不同,指针需要显式解引用,引用编译器替我们解引用处理

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值