引用初探-C++

引用

引用(reference)其实本质就是给已存在的变量起了一个别名,它和它引用的变量共用同一块内存空间

引用的使用方法:类型& 别名 = 引用实体;
但要注意,此处的类型应与引用实体类型保持一致!!!

如下:

	int temp = 10;
	int& a = temp;
	double x = 3.14;
	double& y = x;

要给int型变量temp定义引用a,则其类型即int&,其他类型同理,此处不再赘述。

下面验证引用与引用实体共用内存空间:

	int temp = 10;
	int& a = temp;//temp的第一个引用
	int& b = temp;//temp的第二个引用
	int& c = temp;//temp的第三个引用
	cout << "temp的地址:" << &temp << endl;
	cout << "a的地址:   " << &a << endl;
	cout << "b的地址:   " << &b << endl;
	cout << "c的地址:   " << &c << endl;

上方代码给变量temp定义了三个引用a,b,c,到底是不是共用同一块内存空间,验证如下:
引用初探-C++_第1张图片

4个地址一致,因此引用的实质就是被引用实体的别名没跑了!

特点

1.引用在定义时必须初始化
2.一变量可以拥有多个引用,就像一个人除了自己的本名外,还会有许多称呼一样。
3.一旦引用被定义,那么该引用不能再引用其他实体。即引用从定义那一刻开始,就和被引用实体绑定在了一起。我们根据这一点也就了解为什么引用必须初始化。#
4. 引用只能绑定在对象上,不能与字面值或表达式的计算结果绑定在一起。如下情形都可以证明:
情形1:变量被const修饰

	const int a = 10;
	int& ra = a;

3

结论:变量一旦被const修饰,则普通的【类型& 别名 = 引用实体】用法错误!
情形2:

	int a = 10;
	int b = 20;
	int& ra = a + b;

在这里插入图片描述

结论:引用不能和表达式的计算结果绑定在一起
情形3:

int& ra = 10;

在这里插入图片描述

结论:引用不能和字面常量绑定在一起

But!!!

const int a = 10;
const int& ra = a;
cout << "a的地址:" << &a<<"值:" <<a<<endl;
cout << "ra的地址 " << &ra<< "值:"<<ra<<endl;

在这里插入图片描述

这样是可以的!
结论:被引用实体被const修饰,则引用也要加const进行修饰。被const修饰意味着什么,无非就是不允许修改。

使用场景

1.做参数

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

其实此处的引用完全看成指针,上面的函数等价于

void Swap(int* x, int* y){
	int temp = *x;
	*x = *y;
	*y = temp;
}

2.做返回值
但做返回值这里有坑,我先踩为敬!

int& Add(int x, int y) {
	int sum = x + y;
	return sum;
}
int main() {
	int a = 1, b = 2;
	int& res = Add(a, b);
	cout <<res<<endl;
	return 0;
}

引用初探-C++_第2张图片

结果没得问题!看来的确可以做返回值,但!不要急着下结论,都说了这里有坑,继续看:

我添加一个Destory()函数,咱们再试一次!

int& Add(int x, int y) {
	int sum = x + y;
	return sum;
}
void Destory() {
	int temp[] = { 3,2,1,45,1,2,745,1,2,4 };
	cout << "我要覆盖Add()腾出来的空间" << endl;
}
int main() {
	int a = 1, b = 2;
	int& res = Add(a, b);
	Destory();
	cout <<res<<endl;
	return 0;
}

哎?按理说,这里应该输出3是不?
引用初探-C++_第3张图片
你瞧。结果差的远着哩!为什么呢?原因在于sum是Add()里的一个变量,当Add()运行结束,Add()的空间就被释放了,里面定义的所有东西在内存中虽然存在,但随着Add()的运行结束,下一行代码就让Destory()来了!它开了栈帧,鸠占鹊巢,立马把Add()腾出来的空间占用了,原来的数据也被破坏了!sum地址存的3已经被覆盖了,所以结果不是3了。

那引用到底可不可以做返回值?答案不变啊,可以!

我们只需要用static修饰一下就行了

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

引用初探-C++_第4张图片
结果对了吧,你想覆盖sum?不好意思,static这位保镖不允许你动它。究其根本,就在于static的特性之一:使局部变量的生命周期变全局变量的生命周期。要是有铁子忘了static的三个特性,可以移步这里:
static详解

最后,总而言之:当函数返回时,出了函数作用域,如果返回对象还未返还给系统,那么就可以用引用返回。否则必须使用传值返回。

引用与指针的不同点

1.引用定义时必须初始化,指针则不然
2.引用一旦和对象绑定,则不能再引用其他对象,指针则不然
3.没有NULL引用,存在NULL指针
4.sizeof(引用),返回被引用实体的大小;sizeof(指针),返回值永远都是地址空间所占字节个数(32位平台为4)
5.引用自加,即引用实体自加
指针自加,即指针向后移动一个所指类型的大小
6.存在多级指针,没有多级引用
7.访问方式不同,指针需要显式解引用,引用编译器自己处理。
8.引用与指针相比相对更安全(因为引用不能赋值,出生那一刻就已经决定它是谁了,而指针想是谁就是谁)
9.定义引用不开辟新空间,定义指针需要

效率

以值作为参数或返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为实参或者返回值类型,效率非常低下,尤其当参数或返回值类型非常大时,效率更低。

你可能感兴趣的:(C++,c++)