【C++】类与对象理解和学习(中)

news2024/9/21 14:52:22

专栏放在【C++知识总结】,会持续更新,期待支持🌹


六大默认成员函数

前言

每个类中都含有六大默认成员函数,也就是说,即使这个类是个空类,里面什么都没有写,但是编译器依然会自动生成六个默认成员函数,可以说它们六个是祖师爷钦点的“天选之子”。如下图所示:

这里我们来谈一谈何为默认?默认是有两种情况:

  1. 我们不写,编译器自动生成的

  1. 我们根据规定写的(后面会一一讲到),但是函数参数为全缺省或者不含有函数参数的。

构造函数

首先来谈谈它的作用,就是减少我们手动初始化,实现自动初始化。就比如下面的代码,我们要想对对象进行初始化,就要调用函数Init,会很麻烦,而构造函数就是为了解决这个麻烦的。接下来我们先谈一谈它的创建规则

构造函数的函数名与类名相同
无返回值
对象实例化时编译器自动调用对应的构造函数。
构造函数可以重载(可以存在多个构造函数,但默认构造函数只有一个)

(当然现阶段初始化的方式本质实际上是通过函数体赋值实现,并不是完全意义上的初始化,后面的章节会讲到初始化列表,通过初始化列表实现真正意义上的初始化)

这里还有一个注意点需要注意一但自己写了构造函数,不管是默认构造函数,还是普通构造函数,编译器都不会自动默认生成构造函数。


class Date
{
public:
    普通构造函数
    Date(char a)
    {
        _year = 2023;
        _month = 2;
        _day = 19;
    }
//一但我们自己写了构造函数,不管是属于默认类型的还是普通类型的,编译器都不会自动默认生成
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    //Date d1;//这里编译器会报错,没有合适的默认构造函数,这是因为我们自己写了普通类型的构造函数,编译器就不会再自动生成默认构造函数,而我们的类中又没有写默认构造函数,所以会报错。
    return 0;
}

默认构造函数

上面我们已经讲过默认构造函数的形式,一种是编译器自动生成,另一种是自己根据规则来写但是函数无参数或者参数为全缺省参数。后面的自己写的我们上面讲过了,这里我们来谈一谈编译器自动默认生成的。

我们发现编译器自动生成的默认构造函数竟然没有给我们的数据做初始化处理,这是为啥呢?实际上是我们的祖师爷埋下的一个大坑:默认构造函数对内置类型(int double char...)不做处理,但是对自定义类型(struct class union)会自动调用它所对应的默认构造函数。我们下面来实验一下会发现确实如此:

不过对于这个大坑,C++11中新增了一个补丁(一些老版本的编译器可能不支持)可以在声明时给内置类型一个缺省值:如下

(当然对于构造函数还会有一些比较恶心的地方,我们把它放在后面一章来讲解关于初始化列表相关知识及注意点)

析构函数

析构函数的作用就是对类对象中的资源进行清理,它的创建方式与构造函数大致相同

析构函数名是在类名前加上字符 ~。
无参数无返回值类型。
一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载(只能存在一个,要么是编译器自动生成的,要么是自己写的)
对象生命周期结束时,C++编译系统系统自动调用析构函数

当然,在析构函数这里也存在着一个大坑,与默认构造函数相同,由于析构函数不支持重载,所以我们写的实际上就是默认析构函数,它在清理资源时对内置类型不做处理,对自定义类型会调用该自定义类型的默认析构函数。

因此我们可以这样来说:

对于普通的内置类型,我们不需要写析构函数(写了后我们自己的就是默认析构函数),编译器自动生成的就够用了,但是对于向系统申请空间,涉及到动态内存开辟的,则必须由我们自己写析构函数进行释放资源,不然会造成内存泄漏。

构造与析构的调用顺序

这里简单提一嘴,就是类对象默认构造与默认析构函数的调用顺序与我们学过的一种数据结构——栈类似,先定义的先调用构造,后调用析构(先进后出)

Date d1;
Date d2;
//构造函数调用顺序:d1 d2
//析构函数调用顺序:d2 d1

拷贝构造函数

拷贝构造函数看名字也可以看出来,是属于构造函数的一种重载。作用是完成拷贝工作。它的创造规则如下:

与构造函数相同
这里需要注意的是拷贝构造函数只有一个参数,并且这个参数必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
如果自己没写,编译器会生成默认的拷贝构造,拷贝方式为浅拷贝(值拷贝),对内置类型实现浅拷贝,对自定义类型则调用该自定义类型的拷贝构造函数。

谈一谈无穷递归问题

对于自定义类型,在传值传参的时候会·产生拷贝构造,而调用拷贝构造函数又需要传参,传值传参又会产生拷贝构造...(无限套娃)

正确写法应为传引用传参

    Date(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }

谈一谈深浅拷贝

所谓浅拷贝,其实就是值拷贝一个字节一个字节的完成拷贝,我们的编译器默认生成的就是浅拷贝。所以对于两个上面这种日期类对象,假如实现将d1拷贝给d2,我们可以这么来写:

Date d2(d1);//或者:Date d2=d1;

当然,由于编译器生成的默认拷贝构造既然已经可以实现一个字节一个字节拷贝,也就是浅拷贝(值拷贝),那么对于这种日期类对象,我们可以不写拷贝构造函数,因为编译器自动生成的已经够用了,我们把代码屏蔽,依然可以编译通过,实现拷贝。

那么可能有人会很好奇,既然编译器生成的已经够用了,那么还需要我们自己来写嘛?答案是肯定的,就比如以下这种情况:涉及到空间资源开辟

因此,我们可以这么说:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则浅拷贝会出大问题。

(另外给大家一个小建议:一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用

尽量使用引用,这样做是为了减少拷贝,提高程序运行效率)。

赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载所谓运算符重载的用处是什么呢?实际上就是是我们的自定义类型也可以直接使用操作符进行操作。就比如说,整型a大于整型b,我们可以直接用>进行判断,但是对于自定义类型来说,这里就不能直接使用>。

那么什么是运算符重载呢?实际上运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名为:关键字operator后面接需要重载的运算符符号

函数原型:返回值类型 operator操作符(参数列表)

这里还有以下几点需要注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@

  1. 重载操作符必须有一个类类型参数

  1. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

  1. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

  1. .* :: sizeof ?: . 注意以上5个运算符不能重载。

我们再来谈一谈赋值运算符重载

赋值运算符重载是属于运算符重载中的一种,我们需要注意以下几点:

参数类型:const T&,传递引用可以提高传参效率

返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

另外,我们不要与拷贝构造记混了,拷贝构造是给实例化对象初始化,此时实例化对象还没有创建完成,但赋值是两个都已经实例化后的对象,a的值赋值给b,b=a,此时a与b都是以及实例化后的。
这里我们还需要注意的就是,它是祖师爷钦点的天选之子之一 ,所以即使我们不写,编译器也会生成一个默认赋值运算符重载,但是,我们 写的话只能在类内写,不可以写在全局,这是因为如果类中没有赋值运算符,编译器会自动生成一个,假如此时我们在类外又写了一个,就会发生冲突!

关于默认运算符重载

编译器生成的默认运算符重载,对于内置类型会以值的方式逐字节拷贝(即浅拷贝),对于自定义类型,则会调用该自定义类型的默认运算符重载。(因此,我们上面的这个日期类,我们不写赋值运算符重载,用编译器生成的就够用了)

(当然,与我们上面讲的默认拷贝构造一样 ,如果不涉及到向内存申请空间资源,我们就不需要写,但是一旦涉及到,我们就需要使用深拷贝的方式来实现,原因与拷贝构造那里讲的一样

const成员函数

const成员函数其实就是在成员函数后面加个const,这里的const修饰的是隐含形参:this指针!const放在成员函数后面后,*this即调用这个函数的类对象里的数据便不可以发生修改!

取地址及const取地址操作符重载

这两个我们一般不需要进行重载,用编译器生成的默认的即可(自己返回一个假地址玩一玩的话,也可以自己写着玩)


end

生活原本沉闷,但跑起来就会有风!🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SSD 代码精读】之 model (Backbone) loss

model1、Backbone1)ResNet-502)截取 ResNet-50 的前半部分作为 backbone2、Module3、Loss Function1)location loss2)confidence loss3)整体 loss4)loss 代码1、Backbone 这里介绍使用 ResNet-50 作为 bac…

思维经验 | ​如何刻意练习提升用户思维?

小飞象交流会哪里有什么捷径,那些个“一步登天”的哪个不是在前面就打好了“地基”的。内部交流│20期思维经验分享如何刻意练习提升用户思维?data analysis●●●●分享人:大江老师‍数据部门和运营部门做了大量的用户标签和用户分层工作。为…

基于GIS的地下水脆弱性评价

(一)行政边界数据、土地利用数据和土壤类型数据 本文所用到的河北唐山行政边界数据、土地利用数据和土壤类型数据均来源于中国科学院资源环境科学与数据中心(https://www.resdc.cn/Default.aspx)。 (二)地…

小孩扁桃体肿大3度能自愈吗?6岁小孩扁桃体肥大怎么治效果好?

12月7日,四川眉山市民唐先生说,他刚出生的儿子在妇产医院分娩中心住了20天后感染了败血症。据唐先生介绍,哈子出院时各项指标正常。他在分娩中心住了半个月左右,孩子喝牛奶很生气,第二天就开始发烧了。同一天&#xff…

新版bing(集成ChatGPT)申请通过后在谷歌浏览器(Chrome)上的使用方法

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Flink-运行时架构介绍

文章目录Flink 运行时架构系统架构整体架构作业管理器(JobManager)任务管理器(TaskManager)作业提交流程高层级抽象视角独立模式(Standalone)YARN 集群数据流图(Dataflow Graph)并行…

用户画像——如何构建用户画像系统

为什么需要用户画像 如果你是用户,当你使用抖音、今日头条的时候,如果平台推荐给你的内容都是你感兴趣的,能够为你节省大量搜索内容的时间。 如果你是商家,当你投放广告的时候,如果平台推送的用户都是你的潜在买家,能够使你花更少的钱,带来更大的收益。 这两者背后都…

Linux内核驱动之efi-rtc

Linux内核驱动之efi-rtc1. UEFI与BIOS概述1.1. BIOS 概述1.1.1. BIOS缺点:1.1.2. BIOS的启动流程1.2 UEFI 概述1.2.1 Boot Sevices:1.2.2. Runtime Service:1.2.3. UEFI优点:1.2.4. UEFI启动过程:1.3 Legacy和UEFI1.4 …

【第31天】SQL进阶-写优化- 插入优化(SQL 小虚竹)

回城传送–》《31天SQL筑基》 文章目录零、前言一、练习题目二、SQL思路:SQL进阶-写优化-插入优化解法插入优化禁用索引语法如下适用数据库引擎非空表:禁用索引禁用唯一性检查语法如下适用数据库引擎禁用外键检查语法如下适用数据库引擎批量插入数据语法…

W806(一)模拟IIC驱动0.96OLED[移植]

前言平头哥内核的国产开发板,资源丰富,按照官方的描述是能够吊打STM32F103C8T6的,22年刚发布的时候就买了,但是当时忙于考研,而且开发板的SDK不够完善,所以23年来填一下坑,今年我在官方群里找到…

ChatGPT原理与技术演进剖析

—— 要抓住一个风口,你得先了解这个风口的内核究竟是什么。本文作者:黄佳 (著有《零基础学机器学习》《数据分析咖哥十话》) ChatGPT相关文章已经铺天盖地,剖析(现阶段或者只能说揣测)其底层原…

为啥程序会有bug?

这是一篇半娱乐性的吐槽文章,权当给广大技术人员解解闷:)。哈哈哈,然后我要开始讲一个经常在发生的事实了。(程序员们可能会感到一些不适)99.999999999%做技术的都会被问到或者被吐槽到:“你的程…

PPT和回放来了 | 中国PostgreSQL数据库生态大会圆满落幕

2月17-19日,中国PostgreSQL数据库生态大会在北京中科院软件所和CSDN平台以线下线上结合方式盛大召开!本届大会由中国开源软件推进联盟PostgreSQL分会主办。作为自2017年后我们举办的第六届年度行业大会,延续了传播技术,发展产业生…

代码质量与安全 | 一文了解高级驾驶辅助系统(ADAS)及其开发中需要遵循的标准

高级驾驶辅助系统(ADAS)有助于提高车内每个人的安全性,帮助他们安全抵达目的地。这项技术功能非常重要,因为大多数的严重车祸都是人为错误造成的。 本篇文章将讨论什么是高级驾驶辅助系统(ADAS)&#xff0…

Linux基础-新手必备命令

概述系统工作系统状态检测文件与目录管理文件内容查阅与编辑打包压缩与搜索常见命令图解参考资料概述常见执行 Linux 命令的格式是这样的:命令名称 [命令参数] [命令对象]注意,命令名称、命令参数、命令对象之间请用空格键分隔。命令对象一般是指要处理的…

第三章 Kafka生产问题总结及性能优化实践

第三章 Kafka生产问题总结及性能优化实践 1、线上环境规划 JVM参数设置 kafka 是 scala 语言开发,运行在 JVM 上,需要对 JVM 参数合理设置,参看 JVM 调优专题 修改 bin/kafka-start-server.sh 中的 JVM 设置,假设机器是 32G 内…

Java有几种文件拷贝方式?哪一种最高效?

第12讲 | Java有几种文件拷贝方式?哪一种最高效? 我在专栏上一讲提到,NIO 不止是多路复用,NIO 2 也不只是异步 IO,今天我们来看看 Java IO 体系中,其他不可忽略的部分。 今天我要问你的问题是,…

一个巨型的ESP8266模块,围观围观

作者:晓宇,排版:晓宇微信公众号:芯片之家(ID:chiphome-dy)01 巨型ESP8266ESP8266几乎无人不知,无人不晓了吧,相当一部分朋友接触物联网都是从ESP8266开始的,…

软考中级-嵌入式系统设计师(二)

1、逻辑电路:组合逻辑单路、时序逻辑电路。根据电路是否有存储功能判断。 2、组合逻辑电路 指该电路在任一时刻的输出,仅取决于该时刻的输入信号,而与输入信号作用前电路的状态无关。一般由门电路组成,不含记忆元器件&#xff0…

XD文件转换为sketch的三种方法

XD文件如何转化为Sketch文件,作为竞品的两个产品,如果要互通到可以彼此转换为彼此的文件格式,还是有点难的。所以,今天我总结了 3 个方法,其中最后一个方法是最好用的! XD 和 Sketch 算是竞品,想…