当前位置: 首页 > news >正文

从0到1:C++ 语法之引用

Hello,Hello 大家好,非常高兴又能和大家见面了,我依旧是那一个刚入门编程时间不久,但是对于编程有着极大兴趣的一个菜鸟,还是非常欢迎大家和我进行学习方面的交流,一起努力、一起进步~~~

今天要和大家分享的是 C++ 中的一个非常重要的语法:引用。

一:引用的概念和定义

引用不是新定义一个变量,而是给已经存在的变量取了一个别名,在语法层面上编译器不会为引用变量开辟内存空间(但引用的底层还是指针,本质上还是要开空间的,本文的最后会带大家看),它和引用的变量共同使用同一块内存空间。比如:水浒传中的李逵,宋江叫“”铁牛,江湖人称“黑旋风”;林冲,外号豹子头。

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

#include <iostream>
using namespace std;int main()
{int a = 0;int& b = a; // b是a的别名int& c = a;int& d = b; // 也可以给a的别名起别名,相当于还是给a起别名。++d;cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;return 0;
}

二:引用的使用

引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率,和改变引用对象的同时改变被引用对象

1.引用传参:

引用传参跟指针传参功能是类似的,引用传参相对会跟方便一些。

案例1:

场景:写一个函数实现两个变量的交换。

在学习 C++ 的引用语法之前,我们只能通过指针的方式解决:

#include <iostream>using namespace std;void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}int main()
{int x = 0, y = 1;cout << x << " " << y << endl;Swap(&x, &y);cout << x << " " << y << endl;return 0;
}

传值传参形参是实参的值拷贝,形参的改变并不会影响到实参,因此要传的是两个变量的地址,通过修改指针指向的内容来完成两个变量的交换。

这就显得非常的麻烦~~,一旦我们忘记传地址,就达不到交换变量的效果。

C++ 有了引用之后,就变得简洁、方便了许多:

#include <iostream>using namespace std;void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}int main()
{int x = 0, y = 1;cout << x << " " << y << endl;Swap(x, y);cout << x << " " << y << endl;return 0;
}

此处 rx 和 ry 就是 x 和 y 的别名,完成别名的交换本质上也就完成了两个变量的交换。

在语法层面上,引用传参相对于指针更加容易理解一些,更加顺畅一些。

但是上面两段代码并没有发生质的改变(虽说引用传参会减少拷贝,但指针传参也就拷贝4或8个字节,其实本质上引用传参也会发生拷贝,引用底层还是指针)。

如果单看这个案例不能让你感受到引用相对于指针理解上的顺畅和方便,请看下面的例子:

案例2:

使用 C 语言的指针方式初始化数组栈:

在初始化的时候,一定不要忘记传的应该是地址,传值传参形参是实参的值拷贝,形参的改变并不会影响到实参,st2才能真正完成初始化。

学完引用之后,一切就变得方便很多了:

案例3:终极案例

一些主要的 C 代码实现的数据结构中教材中,使用 C++ 的引用代替指针传参,目的是简化程序,避开复杂的指针。

2.引用作返回值

引用做返回值的场景相对比较复杂,在这里简单讲了一下场景,还有一些内容后续类和对象章节中会继续深入讲解。具体请关注我的动态~~~

现在先在这里做一个简单的理解,后面学到更多知识以后再详细讲解~~

案例:引用做返回值的场景:可以改变临时对象。

int& STTop(ST& rs)
{assert(rs.top > 0);return rs.a[rs.top - 1];
}int main()
{ST st1;STInit(st1);STPush(st1, 1);STPush(st1, 2);STPush(st1, 3);cout << STTop(st1) << endl;STTop(st1) += 10;cout << STTop(st1) << endl;return 0;
}

2.1前置知识

1.左值&右值

左值和右值是一对相对复杂的概念。这里简单理解:可以取地址,可以立刻修改的值就是左值。不可以取地址,无法被修改的值就是右值。

左值举例:普通变量......

右值举例:临时对象、匿名对象、字面量常量。

2.关于越界读和越界写的问题

数组越界读通常是不报错的,越界写有可能会报错。

编译器一般不会检查越界读的问题,对于越界写,编译器会进行抽查(不同编译器检测方式不同)

一般的编译器会在数组越界的部分中设置若干个监测点,在对象销毁的时候检测监测点的信息是否被修改(是否发生越界写)。如果是,就报错。

这也是为什么越界写的问题一般会在 free 的时候报错

2.2对于上面程序的理解

上面的程序如果采用传值返回的话,传值返回生成拷贝产生临时对象(寄存器),临时对象是右值不能够被修改,就会报错。引用做返回值,返回对象是数组中一个元素的别名,可以被修改。

2.3引用做返回值的问题(野引用)

#include <iostream>using namespace std;int& add(int a, int b)
{int c = a + b;return c;
}int main()
{int a = 1, b = 2;add(a, b) += 10;cout << add(a, b) << endl;return 0;
}

三:引用的特性

1.引用在定义时必须初始化

2.一个变量可以有多个引用(一个人可以有多个外号)

3.引用一旦引用一个实体,不能再引用其他实体

#include <iostream>using namespace std;int main()
{int a = 10;// 编译报错:“ra”:必须初始化引用//int& ra;int& b = a;int& d = a;//一个变量可以有多个引用int c = 20;//这里是一个赋值,并非让 b 去引用 c//因为C++的引用不能改变指向b = c;return 0;
}

四:const 引用

第一点:

可以引用一个 const 对象,但是必须用 const 引用const 引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小但是不能放大

int main()
{const int a = 10;// 这样的写法是错误的,这里的引用是对 a 访问权限的放大// int& ra = a;const int& ra = a;// 这里的引用是对 b 访问权限的缩小,是可以的int b = 20;const int& rb = b;// 不会影响到b,b的别名收到限制b++;//rb++;return 0;
}

场景:

void func(int& x)
{//......
}void func(const int& x)
{//......
}int main()
{int a = 10, b = 1;func(a);func(b);func(20);return 0;
}

如果没有实现第二个版本的 func,程序就会报错,因为传参过程中会发生权限的放大

第二点:

需要注意的是类似 int& rb = a * 3; double d = 12.34; int& rd = d; 这样的一些场景下 a * 3 的和结果保留在一个临时对象中,int& rd = d 也是类似,在类型转化中会产生临时对象存储中间值,也就是说,rb 和 rd 都是临时对象,而 C++ 规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。

#include <iostream>using namespace std;int main()
{int a = 10;const int& ra = 30;//int& rb = a * 3;const int& rb = a * 3;double d = 12.34;//int& rd = d;const int& rd = d;return 0;
}

第三点:

所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++ 中把这个未命名的对象叫做临时对象。(传值返回、表达式运算、类型转换)

五:指针和引用的关系

C++ 中指针和引用在实践中相辅相成,功能具有重叠性,但是各自有各自的特点,互相不可替代。

一个只能使用指针不能使用引用的场景:

引用在定义的时候必须初始化,这里没办法初始化。

链表的删除需要改变指向,C++ 中的引用不能改变指向

1.语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。

2.引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。

3.引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以不断地改变引用对     象。

4.引用可以直接访问指向对象,指针需要解引用才能访问指向对象。

5.sizeof 中,引用结果时引用类型的大小,但指针始终是地址空间所占字节个数。

(32位机下4个字节,64位机下8个字节)

6.指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。

引用的底层本质上还是指针

仔细观察,引用和指针转成汇编后底层是一样的。因此引用实际也是会开空间的,但是在语法意义上引用是不开空间的

http://www.dtcms.com/a/332103.html

相关文章:

  • qt项目中解决关闭弹窗后执行主界面的信号槽时闪退问题
  • 基于wireshark的USB 全速硬件抓包工具USB Sniffer Lite的使用
  • 多线程安全和性能测试
  • 珠海社保缴费记录如何打印
  • MyBatis Interceptor 深度解析与应用实践
  • CTFShow PWN入门---Kernel PWN 356-360 [持续更新]
  • 【嵌入式汇编基础】-ARM架构基础(五)
  • c/c++实现 TCP Socket网络通信
  • Docker存储卷备份策略于VPS服务器环境的实施标准与恢复测试
  • Linux 进程与内存布局详解
  • RecyclerView 拖拽与滑动操作
  • HQA-Attack: Toward High Quality Black-Box Hard-Label Adversarial Attack on Text
  • 多列集合---Map
  • 【无标题】设计文档
  • Cache的基本原理和缓存一致性
  • 基于大语言模型的爬虫数据清洗与结构化
  • 可信搜索中的多重签名
  • 系统日常巡检脚本
  • 将mysql数据库表结构导出成DBML格式
  • Qt---Qt函数库
  • ActionChains 鼠标操作笔记
  • # Vue 列表渲染详解
  • AI智能体|扣子(Coze)搭建【批量识别发票并录入飞书】Agent
  • FTP 服务详解:原理、配置与实践
  • 8月14日星期四今日早报简报微语报早读
  • [激光原理与应用-273]:理论 - 波动光学 - 光是电磁波,本身并没有颜色,可见光的颜色不过是人的主观感受
  • 时钟 中断 day54
  • close函数概念和使用案例
  • rustdesk 开源遥控软件
  • 云服务器运行持续强化学习COOM框架的问题