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


    在这里插入图片描述

    🐧主页详情Choice~的个人主页
    📢作者简介:🏅物联网领域创作者🏅 and 🏅阿里专家博主🏅 and 🏅华为云享专家🏅
    ✍️人生格言:最慢的步伐不是跬步,而是徘徊;最快的脚步不是冲刺,而是坚持。
    🧑‍💻人生目标:做一名合格的程序员,做完成的梦:实现财富自由。
    🚩技术方向:NULL
    🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦
    💬给大家介绍一个我一直在用的求职刷题收割offe👉点击进入网站在这里插入图片描述

    🏫系列专栏(免费):
    1️⃣ C语言进阶
    2️⃣ 数据结构与算法(C语言版)
    3️⃣ Linux宝典
    4️⃣ C++从入门到精通
    5️⃣ C++从入门到实战
    6️⃣ JavaScript从入门到精通
    7️⃣101算法JavaScript描述
    8️⃣微信小程序零基础开发
    9️⃣牛客网刷题笔记
    🔟计算机行业知识(补充)

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

    1.引用基本语法

    **引用是c++对c的重要扩充。**在c/c++中指针的作用基本都是一样的,但是c++增加了另外一种给函数传递地址的途径,这就是按引用传递(pass-by-reference),它也存在于其他一些编程语言中,并不是c++的发明。

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

    基本语法:

    Type& ref = val;
    
    • 1

    注意事项:

    • &在此不是求地址运算,而是起标识作用。
    • 类型标识符是指目标变量的类型
    • 必须在声明引用变量时进行初始化。
    • 引用初始化之后不能改变。
    • 不能有NULL引用。必须确保引用是和一块合法的存储单元关联。
    • 可以建立对数组的引用。
    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行结果:

    image-20220803162145166

    image-20220803160150121

    2.引用必须初始化

    image-20220803162412025

    //2.引用必须初始化
    void test02()
    {
    
    	int a = 10;//必须初始化
    	int &b = a;//引用初始哈后不可以进行修改了
    	int c = 20;
    
    	b = c;//赋值!!!
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    第二种数组起别名:

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

    运行结果一样的:image-20220803170942998

    二:函数中的引用

    交换两个变量的值

    1.值传递

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    运行结果:

    swap::a=5
    swap::b=3
    a=3
    b=5
    
    • 1
    • 2
    • 3
    • 4

    原因是函数传递的是形参,一份实参的临时拷贝,当函数结束,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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行结果:

    image-20220803174929477

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

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

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

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

    三:引用的注意事项

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

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

    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="<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    我们看一下结果:

    image-20220803180226435

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

    	cout << "ret=" << ret << endl;
    	cout << "ret=" << ret << endl;
    	cout << "ret=" << ret << endl;
    	cout << "ret=" << ret << endl;
    	cout << "ret=" << ret << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    image-20220803181133560

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

    int& doWork2()
    {
    	//用静态变量试试
    	static int a = 10;
    	return a;
    
    }
    void test05()
    {
    
    	int &ret = doWork2();
    
    	//如果函数的返回值是引用,那么这个函数调用可以作为左值
    
    	doWork2() = 1000;//相当于写了a=1000;
    	cout << "ret=" << ret << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    image-20220803181917713

    四:引用的本质

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

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

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    五 :指针的引用

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

    void fun(int**);
    
    • 1

    给指针变量取一个别名。

    Type* pointer = NULL;  
    Type*& = pointer;
    
    • 1
    • 2

    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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    **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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    image-20220803184029840

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

    六:常量引用

    常量引用的定义格式:

    const Type& ref = val;
    
    • 1

    常量引用注意:

    • n字面量不能赋给引用,但是可以赋给const引用
    • const修饰的引用,不能修改。
    void test01()
    {
    
    	//int &ref = 10;//引用了不合法的内存,不可以
    
    	const int &ref = 10;//加入const后,编译器处理方式为:int tmp=10;const int &ref=tmp;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    尝试修改常量的值:

    image-20220803184536761

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

    int *p = (int*)&ref;
    	*p = 1000;
    
    • 1
    • 2

    image-20220803184814419

    const引用使用场景

    常量引用主要用在函数的形参,尤其是类的拷贝/复制构造函数。

    将函数的形参定义为常量引用的好处:

    Ø 引用不产生新的变量,减少形参与实参传递时的开销。

    Ø 由于引用可能导致实参随形参改变而改变,将其定义为常量引用可以消除这种副作用。

    如果希望实参随着形参的改变而改变,那么使用一般的引用,如果不希望实参随着形参改变,那么使用常引用。

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

    重点回顾

    6 引用基本语法

    6.1.1 用途起别名

    6.1.2 Type &别名 = 原名

    6.1.3 引用必须初始化

    6.1.4 一旦初始化后 不能修­­改

    6.1.5 对数组建立引用

    6.2 参数3种传递方式

    6.2.1 值传递

    6.2.2 地址传递

    6.2.3 引用传递

    6.3 注意事项,不要返回局部变量的引用

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

    6.5 引用的本质 就是一个指针常量

    7 指针的引用

    7.1 用一级指针引用 可以代替二级指针

    8 常量引用

    8.1 使用场景 修饰形参为只读

    8.2 const int &a = 10;会分配内存

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

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

    • 如果对大家有帮助,请三连支持一下!
    • 有问题欢迎评论区留言,及时帮大家解决!
      在这里插入图片描述
  • 相关阅读:
    计算机网络实验一 交换网络组建
    【Git 学习笔记】第三章 分支、合并及配置项(下)
    WINDOWS+PHP+Mysql+Apache环境中部署SQLi-Labs、XSS-Labs、UPload-Labs、DVWA、pikachu等靶场环境
    【KD】Transformer在各个研究领域的轻量化研究进展
    SystemVerilog 控制流语句
    Codeforces Round #818 (Div. 2) E. Madoka and The Best University(gcd性质+莫比乌斯反演φ)
    零基础学习CSS
    如何安装和使用Docker
    对接钉钉Stream模式考勤打卡相关事件的指南
    centos 搭建内网ntp时间服务器
  • 原文地址:https://blog.csdn.net/weixin_51568389/article/details/126149483