【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)
🔥个人主页:Forcible Bug Maker
🔥专栏:C++
目录
前言
类的6个默认成员函数
构造函数
概念
构造函数的特性及用法
析构函数
概念
析构函数的特性及用法
结语
前言
本篇主要内容:类的6个默认成员函数中的构造函数和析构函数
进入到类和对象内容的第二节,上篇博客中介绍了类和对象的一些基本特性,接下来就要讲到类的六个默认成员函数。C++类的六个默认成员函数包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载。这些函数在特定情况下会被编译器自动生成,但你也可以根据需要自定义它们。
类的6个默认成员函数
在一个类中,如果你什么都不往里写,那么就可以称这个类为空类。实际上,在你什么都不往空类里写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
// 这是一个空类
class Date {};
构造函数、析构函数、拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载。
构造函数
概念
接下来举个例子引入构造函数。如果你写了一个存储日期的类(Date),在使用Date定义的对象之前,都需要像C语言一样调用一遍初始化。
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Init(2022, 7, 5);d1.Print();Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}
你看,使用对象d1和d2之前都需要调用一遍Init函数来给对象设置日期,但如果每次创建对象时都调用该方法,未免有些麻烦,是否存在某种方式,在创建对象时,就将信息设置进去呢?答案是有的,解决方式就是今天的构造函数。
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
构造函数的特性及用法
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
1. 函数名和类名相同。
2. 无返回值(不是void,而是根本就不用写其返回值)。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载:
class Date
{
public:// 1.无参构造函数Date(){}// 2.带参构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
void TestDate()
{Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数
}
注:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明。
Date d3();
如果你写下这样一行代码来创建对象,就大错特错了。这句话会被编译器解读成一种函数声明(其细节是:声明了d3函数,该函数无参,返回一个日期类型的对象),无法达到创建对象的目的。
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成:
其中定义了传参的构造函数,无参的默认构造将被覆盖,也就是说,此时定义变量不传参会编译失败,报错:error C2512: “Date”: 没有合适的默认构造函数可用。
6. C++把类型分成内置类型(基本类型)和自定义类型。对于内置类型,C++默认生成的构造函数对内置类型不做处理(所以未定义自定义类型中的数据为随机值),对自定义类型的成员,会去调用它的默认构造(不用传参数的构造)。内置类型就是语言提供的数据类型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型。
就比如上面的代码,Date类中默认生成的构造函数调用了自定义类型 _t 的无参构造函数。
注:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。
上面代码给了内置类型缺省值,在生成d对象之后,内置类型也就成功被缺省值赋值了。
7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
注:默认构造:不传参就可以调用的函数。故:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。
class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
// 以下测试函数能通过编译吗?
void Test()
{Date d1;
}
根据第七点,我们知道Test函数是不能通过编译的,在类中定义了两个默认构造(不传参就可以调用的构造函数),编译器无法确认应该调用哪一个,模棱两可的代码是编程的大忌。
析构函数
概念
通过了前面构造函数的学习,我们认识了可以在创建对象时帮助初始化的函数,那相应的,是否就应该有对对象进行自动销毁和清理的函数呢?答案是有的。
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
析构函数的特性及用法
析构函数是特殊的成员函数,它在对象的生命周期结束时自动被调用,用于执行清理工作,如释放动态分配的内存、关闭打开的文件、断开网络连接等。析构函数与类名同名,但前面加上一个波浪号(~),并且没有返回类型和参数。
1. 析构函数名是在类名前加上字符 ~ 。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。
4. 对象生命周期结束时,C++编译系统自动调用析构函数。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}
上份代码可以把重点放在构造函数和析构函数上。在构造函数Stack中,使用malloc在堆上开辟了一块空间,使用内置类型 _capacity 和 _size 来维护整个栈;最后定义了析构函数~stack,在此函数中,我们在函数内部实现了堆中占用内存的释放。
什么?你告诉我你不知道什么是栈?推荐你看看这篇博客:初阶数据结构之---栈和队列(C语言)
指针类型属于内置类型
如果不自己实现析构函数,编译器会将_array当作内置类型,在自动生成的析构函数中不会释放堆中占用的空间,导致内存泄露。
5. 关于编译器自动生成的析构函数,和构造函数很类似:编译器生成的默认析构函数,对内置类型成员不做处理;对于自定义类型的成员,调用它的析构函数。
class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
你会发现,在main方法中根本就没有直接创建Time类的对象,但是最后还是调用了Time类的析构函数。是因为在main方法中创建了Date对象d,而d中包含4个成员变量,其中_year,_month,_day三个是内置类型成员,销毁时不需要资源清理,最后直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含Time类的_t对象销毁,所以要调用Time类的析构函数。但是,main函数中不能直接调用Time类的析构函数,实际释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显示提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数,即当Date对象销毁时,能保证内部每个定义的对象都可以正确销毁。
注:创建哪个类的对象则调用该类的析构函数,销毁哪个类的对象则调用该类的析构函数
6. 类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如:Date类;有资源申请时,一定要写,否则会造成内存泄露,如Stack类。
结语
本篇博客将重点放在了类和对象六个默认成员函数的前两个:构造函数和析构函数上。这两个默认成员函数在对象的生命周期中起着至关重要的作用。构造函数确保对象在创建时能够正确初始化,而析构函数则确保对象在销毁时能够正确清理资源,从而保持程序的稳定性和安全性。在下一篇博客中,我会介绍拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载(另外四大默认成员函数)的内容,敬请期待。
本篇博客到此结束,感谢大家的支持!♥
相关文章:
【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)
🔥个人主页:Forcible Bug Maker 🔥专栏:C 目录 前言 类的6个默认成员函数 构造函数 概念 构造函数的特性及用法 析构函数 概念 析构函数的特性及用法 结语 前言 本篇主要内容:类的6个默认成员函数中的构造函…...
【ZZULIOJ】1063: 最大公约与最小公倍(Java)
目录 题目描述 输入 输出 样例输入 Copy 样例输出 Copy 提示 code 题目描述 输入两个正整数,输出其最大公约数和最小公倍数。 输入 输入两个正整数n和m(n,m<1000000)。输入保证最终结果在int范围内。 输出 输出两个整数,用空格…...
遍历列举俄罗斯方块的所有形状
以前玩俄罗斯方块的时候,就想过一个问题,为什么俄罗斯方块就这7种形状,还有没有别的形状?自己也在纸上画过,比划来比划去,确实就这几种形状。 继续思考一下,那假如是3个块组合的形状࿰…...
将Visio绘图导出PDF文件,使其自适应大小,并去掉导入Latex的边框显示
问题描述 将Visio绘图导成pdf文件,首先在Visio绘图如下: 如果直接导出或者另存为pdf文件,则会发现pdf文件是整个页面大小,而不是图片大小。而且在导入latex等排版工具现实时,会显示边框。 问题解决 1.调整Visio中的页…...
android支付宝接入流程
接入前准备 接入APP支付能力前,开发者需要完成以下前置步骤。 本文档展示了如何从零开始,使用支付宝开放平台服务端 SDK 快速接入App支付产品,完成与支付宝对接的部分。 第一步:创建应用并获取APPID 要在您的应用中接入支付宝…...
Mac 下 Python+Selenium 自动上传西瓜视频
背景 研究下 PythonSelenium 自动化测试框架,简单实现 Mac 下自动化批量上传视频西瓜视频并发布,分享给需要的同学(未做过多的异常处理)。 脚本实现 首先通过手工手机号登录,保存西瓜视频网站的 cookie 文件 之后加载…...
六:ReentrantLock —— 可重入锁
目录 1、ReentrantLock 入门2、ReentrantLock 源码解析2.1、构造方法:默认为非公平锁2.2、三大内部类2.2、lock():加锁【不可中断锁】2.2.1、acquire() 方法 —— AQS【模板方法】2.2.2.1 tryAcquire() 方法 —— AQS,由子类去实现2.2.2.2. a…...
一种驱动器的功能安全架构介绍
下图提供了驱动器实现安全功能的架构 具有如下特点: 1.通用基于总线或者非总线的架构。可以实现ethercat的FSOE,profinet的profisafe,或者伺服本体安全DIO现实安全功能。 2.基于1oo2D架构,安全等级可以达到sil3。 3.高可用性。单…...
紫光展锐T610平台_4G安卓核心板方案定制开发
紫光展锐T610核心板配备Android 11操作系统,采用12nm制程工艺。该处理器CPU由2颗基于Cortex-A75架构的大核心和6颗基于Cortex-A55架构的小核心组成,最高主频为1.8GHz。GPU采用的是614.4MHz的Mali G52,可以流畅播放2400*1080分辨率视频&#x…...
C++11 设计模式4. 抽象工厂(Abstract Factory)模式
问题的提出 从前面我们已经使用了工厂方法模式 解决了一些问题。 现在 策划又提出了新的需求:对于各个怪物,在不同的场景下,怪物的面板数值会发生变化, //怪物分类:亡灵类,元素类,机械类 …...
第8周 Python面向对象编程刷题
单击题目,直接跳转到页面刷题,一周后公布答案。加入QQ群701657573,随时答疑交流。 218:类对象属性219:坐标对象相加220:计算周长221:学生分数总和222:车辆类中创建引擎类对象223&am…...
【学习心得】神经网络知识中的符号解释②
我在上篇文章中初步介绍了一些神经网络中的符号,只有统一符号及其对应的含义才能使我自己在后续的深度学习中有着一脉相承的体系。如果对我之前的文章感兴趣可以点击链接看看哦: 【学习心得】神经网络知识中的符号解释①http://t.csdnimg.cn/f6PeJ 一、…...
Igh related:Small Bug And Notes Record.
Write at the top My computer got some silly problem with the typing software that my Chinese IM does’t work again. So I’ll try to record the things happened in English. If any error,DM me plz. BUGs BUG1 Undefined symbol Identifier “CLOCK_MONOTONIC”…...
【QT入门】Qt自定义控件与样式设计之qss介绍(Qt style sheet)
往期回顾: 【QT入门】 无边框窗口设计之实现圆角窗口-CSDN博客【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口-CSDN博客 【QT入门】 无边框窗口设计之综合运用,实现WPS的tab页面-CSDN博客 【QT入门】Qt自定义控件与样式设计之qss介绍…...
[ LeetCode ] 题刷刷(Python)-第49题:字母异位词分组
题目描述 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词是由重新排列源单词的所有字母得到的一个新单词。 即将含有相同字符但排列顺序不同的字符串放入同一个组中。 示例 示例 1: 输入: strs ["eat", &qu…...
冒泡排序算法实现步骤
算法实现的过程: 1. 定义问题: - 算法是用来解决某一特定计算问题的方法步骤。例如,对于排序问题,我们需要一个算法对一组无序的整数进行排序。 2. 设计算法: - 冒泡排序是一种基础的排序算法。它的设计思路是…...
js实现webp转png/jpg
网上保存的图片是webp类型的,但是我把它嵌入flac格式的音频里后导致网页中无法播放 wps要会员,真麻烦。 完整代码: <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8">…...
DVWA -File Upload-通关教程-完结
DVWA -File Upload-通关教程-完结 文章目录 DVWA -File Upload-通关教程-完结页面功能LowMediumHighImpossible 页面功能 此页面的功能为选择某个图片文件点击Upload按钮上传,上传成功后得知文件上传路径为DVWA\hackable\uploads。 Low 源码审计 这段 PHP 代码…...
中介者模式:简化对象间通信的协调者
在面向对象的软件开发中,中介者模式是一种重要的行为型设计模式,用于降低多个对象间通信的复杂性。通过提供一个中心化的对象来处理不同组件之间的交互,中介者模式使得组件间不必显式引用彼此,从而使其松散耦合、更易于维护。本文…...
【Python系列】pydantic版本问题
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
深度学习-多尺度训练的介绍与应用
一、引言 在当今快速发展的人工智能领域,多尺度训练已经成为了一种至关重要的技术,特别是在处理具有复杂结构和不同尺度特征的数据时。这种技术在许多应用中发挥着关键作用,例如图像识别、自然语言处理和视频分析等。 多尺度训练的定义 多尺…...
详解单文件组件
当你创建 Vue 单文件组件时,通常会包含三个部分:<template>、<script> 和 <style>。这三个部分分别用于定义组件的模板、逻辑和样式。让我更详细地解释一下它们的作用和用法: <template> <template> 标签用于…...
MLeaksFinder报错
1.报错:FBClassStrongLayout.mm 文件:layoutCache[currentClass] ivars; 解决:替换为layoutCache[(id)currentClass] ivars; 2.编译正常但运行时出现crash indirect_symbol_bindings[i] cur->rebinding FBRetainCycleDetector iOS15 …...
【心路历程】初次参加蓝桥杯实况
送给大家一句话: 寂静的光辉平铺的一刻,地上的每一个坎坷都被映照得灿烂。 – 史铁生 《我与地坛》 初次参加蓝桥杯有感 一点小小的震撼难评的做题过程A题 艺术与篮球问题描述解题 B 题 五子棋问题描述解题 C题 训练士兵问题描述解题 D题 团建解题 E题 …...
微信小程序全屏开屏广告
效果图 代码 <template><view><!-- 自定义头部 --><u-navbar title" " :bgColor"bgColor"><view class"u-nav-slot" slot"left"><view class"leftCon"><view class"countDown…...
记录day1
1.早上 ①协同过滤算法 基于物品基于用户分别是如何实现的 相似度的计算方式 基于用户和基于物品的区别 实时性和新物品这里: 实时性指的是用户有新行为,这样基于物品就好,因为用户新行为了,用户矩阵不会变化,用户…...
stm32GPio的开发基础
上拉输入:高电平(弱高电平,一般默认) 下拉输入:低电平 没有上拉下拉就是处于一个不确定的状态 推挽wan输出:驱动能力比较强,推挽是因为往外推 set就是1,reset就是0 XMX就是封装的…...
DataSource
目录 1、 DataSource 1.1、 * 建立数据库连接的参数对象 1.1.1、 * 数据库url 1.1.2、 * 数据库用户名 1.1.3、 * 数据库密码 1.1.4、 * 数据库驱动名称 <...
Linux防止暴力破解密码脚本
1.认识记录linux记录安全的日志 [roottestpm ~]# cd /var/log/ [roottestpm log]# ls | grep secure secure 2.该日志的内容查看 [roottestpm log]# tail -f secure #表示ssh身份验证失败 Aug 29 23:35:03 testpm sshd[111245]: pam_unix(sshd:auth): authentication fa…...
Unity 遮罩
编辑器版本 2017.2.3f1 学习Unity的三张遮罩方式 1. Mask 遮罩方式 首先,在界面上创建2个Image,一个命名Img_Mask,大小设置 400* 400, 一个命名Img_Show,大小设置500*500。 然后,给 Img_Mask添加Mask,选择Img_Mask,点击Add Com…...
济南正规网站建设公司/大一网页设计作业成品免费
图论学习:https://blog.csdn.net/Fire_to_cheat_/article/details/80028763 关于图的几个概念定义: 连通图: 在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图。强连通图: 在有向图…...
wordpress最新文章插件/全网营销推广
本文给出的java毕业设计开题报告,仅供参考!(具体模板和要求按照自己学校给的要求修改) 选题目的和意义 目的:中国经济飞速发展,社会城市化建设的脚步不断加快,社会城市化的规模也在不断扩大&a…...
商城网站开发的任务书/广州信息流推广公司排名
http://www.springframework.net/doc-latest/reference/html/web.html转载于:https://blog.51cto.com/yerik/1076409...
闵行做网站费用/清远网站seo
目录 在前面的章节中,我们是通过动态创建子进程(或子线程)来实现并发服务器的。这样做有如下缺点: 动态创建进程(或线程)是比较耗费时间的,这将导致较慢的客户响应。动态创建的子进程…...
做鸭网站/如何在百度做推广
一.RF之UI自动化测试环境 1:通过pip安装扩展库: pip install robotframework-seleniumlibrary 2.:下载谷歌游览器和对应驱动 https://www.cnblogs.com/loved-wangwei/p/8993013.html 3.将游览器驱动放在python的目录下 比如:我的python安装在D:\install…...
淮安做网站的公司有哪些公司/360开户
文|柯鸣 来源|智能相对论(aixdlun) 试想一下,一个静谧的午夜,你和家人正在熟睡,家中突然响起毛骨悚然的笑声,时远时近,这困扰了大人,惊吓了孩子。而这一切的怪笑,都是由…...