0
点赞
收藏
分享

微信扫一扫

面向对象之【探索C++】硬核 | 造轮子的快乐源泉【引用篇】

流沙雨帘 2022-08-04 阅读 9

文章目录

一:引用的基础语法以及注意事项

1.引用基本语法

  • 变量名实质上是一段连续内存空间的别名,是一个标号(门牌号)
  • 程序中通过变量来申请并命名内存空间
  • 通过变量的名字可以使用存储空间

基本语法:

Type& ref = val;

注意事项:

  • &在此不是求地址运算,而是起标识作用。
  • 类型标识符是指目标变量的类型
  • 必须在声明引用变量时进行初始化。
  • 引用初始化之后不能改变。
  • 不能有NULL引用。必须确保引用是和一块合法的存储单元关联。
  • 可以建立对数组的引用。
#include<iostream>
using namespace std;

//1.引用基本语法 Type &别名 = 原名
void test01()
{
	int a = 10;
	int &b = a;

	b = 20;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

int main()
{

	test01();

	return 0;
}

运行结果:

image-20220803162145166

image-20220803160150121

2.引用必须初始化

image-20220803162412025

//2.引用必须初始化
void test02()
{

	int a = 10;//必须初始化
	int &b = a;//引用初始哈后不可以进行修改了
	int c = 20;

	b = c;//赋值!!!
}

3.对数组建立引用

image-20220803163558933

//3.数组起别名
void test03()
{
	int arr[10];
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i;

	}
	//数组起别名
	int(&pArr)[10] = arr;
	for (int i = 0; i < 10; i++)
	{
		cout << pArr[i] << " ";
	}
	cout << endl;
}

第二种数组起别名:

	//第二种方式 起别名
	typedef int(ARRAYREF)[10];//一个具有10个元素的int类型的数组
	ARRAYREF & pArr2 = arr;
	for (int i = 0; i < 10; i++)
	{
		cout <<pArr2[i] << " ";
	}

运行结果一样的:image-20220803170942998

二:函数中的引用

交换两个变量的值

1.值传递

#include<iostream>
using namespace std;
//值传递
void swap(int a, int b)
{
	int tmp = a;
	a = b;
	b = tmp;
	cout << "swap::a=" << a << endl;
	cout << "swap::b=" << b << endl;
}

void test01()
{
	int a = 3;
	int b = 5;
	swap(a, b);//值传递
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
}
  
int main()
{
	test01();

	return 0;
}

运行结果:

swap::a=5
swap::b=3
a=3
b=5

原因是函数传递的是形参,一份实参的临时拷贝,当函数结束,swap的数据就消失了

2.地址传递

然后我们用指针的方式交换两个变量的值:

void swap(int *a, int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
}


void test02()
{
	int a = 3;
	int b = 5;
	swap(&a, &b);//地址传递
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

}

image-20220803174457342

3. 引用传递

&引用传递类似于传地址,这就是c++的特性,引用这块,就不用再使用二级指针了;需要用引用表达二级指针*&a

void swap3(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
  
void test03()
{
	int a = 3;
	int b = 5;
	swap(a, b);
	cout << "引用传递的a=" << a << endl;
	cout << "引用传递的b=" << b << endl;
}

运行结果:

image-20220803174929477

通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单:

  1. 函数调用时传递的实参不必加“&”符

  2. 在被调函数中不必在参数前加“*”符

引用作为其它变量的别名而存在,因此在一些场合可以代替指针。C++主张用引用传递取代地址传递的方式,因为引用语法容易且不易出错。

三:引用的注意事项

1.引用必须引一块合法的内存空间

void test04()
{
    //错误
	int &a = 10;//引用必须是一块合法的空间
}

image-20220803175413496

后期我们可以用const给他强制初始化一块空间const int &a = 10;

2.不要返回局部变量的引用

int& doWork()
{
	int a = 10;
	return a;
}
void test04()
{
	//error
	//int &a = 10;//引用必须是一块合法的空间

	int &ret = doWork();
	cout << "ret="<<ret << endl;

}

我们看一下结果:

image-20220803180226435

我们试试用多个输出看看:

	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;

image-20220803180358441

这是因为:第一次输出10编译器做了优化,编译器做的好事;当我们第一次输出10的时候,函数doWork会被销毁,再次调用的时候就找不到了,就会出现乱码,所以不要返回局部变量引用

我们用static修饰为静态变量

int& doWork2()
{
	//用静态变量试试
	static int a = 10;
	return a;

}
void test05()
{

	int &ret = doWork2();
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
}

image-20220803181133560

3.函数调用可为左值,函数返回值需引用

int& doWork2()
{
	//用静态变量试试
	static int a = 10;
	return a;

}
void test05()
{

	int &ret = doWork2();

	//如果函数的返回值是引用,那么这个函数调用可以作为左值

	doWork2() = 1000;//相当于写了a=1000;
	cout << "ret=" << ret << endl;
}

image-20220803181917713

四:引用的本质

引用的本质在c++内部实现是一个指针常量.

Type& ref = val; // Type* const ref = &val;

c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见。

//发现是引用,转换为 int* const ref = &a;
void testFunc(int& ref){
	ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
	int a = 10;
	int& aRef = a; //自动转换为 int* const aRef = &a;这也能说明引用为什么必须初始化
	aRef = 20; //内部发现aRef是引用,自动帮我们转换为: *aRef = 20;
	cout << "a:" << a << endl;
	cout << "aRef:" << aRef << endl;
	testFunc(a);
	return EXIT_SUCCESS;
}

五 :指针的引用

在c语言中如果想改变一个指针的指向而不是它所指向的内容,函数声明可能这样:

void fun(int**);

给指针变量取一个别名。

Type* pointer = NULL;  
Type*& = pointer;

Type* pointer = NULL; Type*& = pointer;

1.指针的指针开辟空间:

void allocatMeMory(Person **p)//**p具体的Person对象  *p对象的指针 p指针的指针
{
	*p =(Person*)malloc(sizeof(Person));
	(*p)->m_Age = 100;

}
void test01()
{
	Person *p = NULL;
	allocatMeMory(&p);
	cout << "p的年龄:" << p->m_Age << endl;

}

**p具体的Person对象 *p对象的指针 p指针的指针

2.利用指针的引用开辟空间

//指针引用
void allocatMemoryByRef(Person * &p)//使用引用取别名
{
	p = (Person*)malloc(sizeof(Person));
	p->m_Age = 1000;

}
void test02()
{
	Person *p = NULL;
	allocatMemoryByRef(p);
	cout << "p的年龄:" << p->m_Age << endl;

}

image-20220803184029840

对于c++中的定义那个,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。

六:常量引用

常量引用的定义格式:

const Type& ref = val;

常量引用注意:

  • n字面量不能赋给引用,但是可以赋给const引用
  • const修饰的引用,不能修改。
void test01()
{

	//int &ref = 10;//引用了不合法的内存,不可以

	const int &ref = 10;//加入const后,编译器处理方式为:int tmp=10;const int &ref=tmp;

}

产生一个临时变量tmp:int tmp=10;const int &ref=tmp;

尝试修改常量的值:

image-20220803184536761

通过加入下面的代码修改ref值(不建议)

int *p = (int*)&ref;
	*p = 1000;

image-20220803184814419

const引用使用场景

//const int& param防止函数中意外修改数据
void ShowVal(const int& param){
	cout << "param:" << param << endl;
}

重点回顾

上一篇【C++】VS【C】之 const 大战(揭开常量的秘密)

首篇面向对象之【探索C++】硬核 | 造轮子的快乐源泉

  • 如果对大家有帮助,请三连支持一下!
  • 有问题欢迎评论区留言,及时帮大家解决!
    在这里插入图片描述
举报

相关推荐

0 条评论