【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;
}

如上面的代码,每次创建一个日期类对象后,都要手动的去调用Init函数,完成对象的初始化,整个过程繁琐,而且容易遗忘,为此,提出了构造函数的概念。

📖定义
构造函数是一个特殊的成员函数名字与类名相同,创建对象的时候由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象的整个生命周期中只调用一次

📖构造函数的特性

  • 函数名与类名相同。
  • 无返回值。(无需void)
  • 对象实例化时编译器自动调用对应的构造函数。
  • 构造函数可以重载。

🎊示例:

 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();}

注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明。即Date d3();是声明了一个d3函数,该函数无参,返回一个日期类对象,并不是创建了一个日期类对象d3

构造函数在语法上可以是私有的,但是在创建对象的时候就调不动了。在单例模式中,会把构造函数搞成私有,具体的我们以后再说。

📖编译器生成的构造函数
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器将不在生成。

🎊示例:

class Date
{public:/*// 如果用户显式定义了构造函数,编译器将不再生成Date(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;return 0;
}

将Date类中的构造函数注释掉后,代码可以编译通过,因为编译器生成了一个无参的默认构造函数。将Date类中的构造函数放开后,代码编译失败,因为一旦显式定义了任何构造函数,编译器将不再生成默认构造函数。而此时Date中的构造函数需要三个参数,Date d1;会去调用无参的构造函数,但是当前类中没有无参的构造函数,所以编译会报错。

📖编译器生成的构造函数干了什么?
C++中把类型分为内置类型自定义类型。内置类型就是语言提供的数据类型,如:intchar……自定义类型就是我们使用classstructunion等自己定义的类型。(所有类型的指针都属于内置类型)。

编译器生成的默认构造函数,对内置类型不做处理,对自定义类型,会去调用它的默认构造函数

🎊示例:

//先定义一个时间类
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
//再定义一个日期类
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

在这里插入图片描述

上面代码,先定义了一个时间类Time,它的成员变量都是内置类型,给这个类写了一个无参的构造函数,接下来,定义了一个日期类Date,他有四个成员变量,其中_year_month_day都是内置类型,_t是自定义类型,并且,我们没有写日期类的构造函数,这意味着,在创建对象的时候,会去使用编译器生成的无参默认构造函数。

📖内置类型给默认值
C++11中针对内置类型成员不初始化的缺陷,打了补丁,即:内置类型成员变量在类中声明时可以给默认值

🎊示例:

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
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;
}

在这里插入图片描述

📖默认构造函数
我们没写编译器自动生成的构造函数无参构造函数全缺省构造函数,这三种都叫做默认构造函数,它们都有一个共同的特点:可以不用传参。默认构造函数只能有一个,后面俩,在语法上可以构成函数重载,但是在无参调用的时候,会发生歧义,出现调用不明确。
在这里插入图片描述
注意:要把默认构造函数和默认成员函数区分清楚,默认成员函数是我们不写编译器会自动生成的,默认构造函数是不需要传参的构造函数。编译器生成的构造函数,既是默认构造函数,同时也是默认成员函数。

📖总结
一般情况下,都需要我们自己写构造函数。如果满足以下情况,即:内置类型的成员变量都有默认值,且初始化符合我们的要求,自定义类型都定义了默认构造,此时可以考虑不写构造函数,使用编译器自动生成的默认构造函数。自定义类型如果没有对应的构造函数,那就意味着初始化自定义类型需要传参,此时必须自己写构造函数,并且还会用到初始化列表。

三、析构函数

📖定义
与构造函数的功能相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。而对象在销毁的时候,会自动调用析构函数,完成对象中资源的清理工作

📖特性

  • 析构函数名是在类名前加上~
  • 无参数无返回值类型
  • 一个类只能有一个析构函数,若未显式定义,系统会自动生成默认的析构函数
  • 对象生命周期结束时,C++编译器自动调用析构函数

小Tips:析构函数不能重载。

🎊示例:

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中的成员变量_array_capacity_size都是内置类型,所以在对象s生命周期结束要销毁的时候,不需要资源清理,最后系统直接将其内存回收即可,而_array指向的空间是在堆区上申请的,这块空间不会随着对象生命周期的结束而自动释放(归还给操作系统),所以_array被回收后,就找不到动态申请的那块空间,会造成内存泄漏,因此在对象销毁前,要通过析构函数去释放成员变量_array指向的空间,这就是析构函数的作用。

📖编译器生成的析构函数干了什么?
我们不写,编译器会自动生成一个析构函数。该析构函数对内置类型不做处理,对自定义类型会去调用它的析构函数

🎊示例:

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方法中创建了Date对象d,而d中包含4个成员变量,其中_year_month_day、三个是内置类型成员,对象销毁时不需要资源清理,最后系统直接将其内存回收即可,而_tTime类对象,在d销毁时,要将器内部包含的Time类的_t对象销毁,所以要去调用Time类的析构函数。但是main函数中不能直接调用Time类的析构函数,实际销毁的是Date类对象d,所以编译器会调用Date类的析构函数,而Date类没有显示提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数。

📖总结
一般情况下,有动态申请资源,就需要显式的写析构函数来释放资源,没有动态申请的资源,可以不写析构函数,需要释放资源的成员都是自定义类型,也不需要写析构函数。


🎁结语:
 今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是春人前进的动力!
在这里插入图片描述

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

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

相关文章

【http-server】http-server的安装、前端使用http-server启动本地dist文件服务:

文章目录 一、http-server 简介:二、安装node.js:[https://nodejs.org/en](https://nodejs.org/en)三、安装http-server:[https://www.npmjs.com/package/http-server](https://www.npmjs.com/package/http-server)四、开启服务&#xff1a;五、http-server参数&#xff1a;【1…

Vscode配置grpc+c#+proto

首先是环境配置&#xff0c;用的dotnet5.0的sdk&#xff0c;所以Vscode的C#插件版本要选择1.24&#xff0c;然后需要配置C# Snippets、NuGget Package Manager、vscode-proto3、vscode-solution-extension&#xff08;可选&#xff09;。 以vscode-solution-extension为例新建A…

在 Linux 系统上下载 Android SDK

使用ubuntu系统进行车机开发&#xff0c;今天开始配置环境&#xff0c;首先是下载android studio&#xff0c;然后下载android sdk&#xff0c;这里需要注意的是linux系统不能使用windows系统下的Android sdk&#xff0c;亲测会出现各种问题。 常规思路&#xff0c;下载sdk&am…

Jenkins的几种安装方式以及邮件配置

目录 Jenkins介绍 Jenkins下载、安装 一、通过war包安装 二、通过docker安装 jenkins 容器中添加 git, maven 等组件 jenkins 容器中的公钥私钥 在 jenkins 容器中调用 docker 简单的方式启动 Docker server REST API 一个 jenkins 示例 三、通过Homebrew安装 访问Je…

oceanbase基础

与mysql对比 分布式一致性算法 paxos 存储结构&#xff08;引擎&#xff09;用的是两级的 数据库自动分片功能&#xff0c;提供独立的obproxy路由写入查询等操作到对应的分片 多租户 方便扩展 存储层 http://www.hzhcontrols.com/new-1391864.html LSM tree&#xff0c;is very…

【cfengDB】自己实现数据库第0节 ---整体介绍及事务管理层实现

LearnProj 内容管理 MySQL系统结构一条SQL执行流程 cfengDB整体结构事务管理TM模块TID文件规则定义文件读写 -- NIORandomAccessFile、FileChannel、ByteBuffer接口实现文件合法检测begin()commit(tid)rollback(tid)tid文件创建 本文作为数工底层的项目CfengDB开始篇章&#xf…

UART串口通信协议

一、串行通信 串行通信分为两种方式&#xff1a;同步串行通信和异步串行通信。 同步串行通信需要通信双方在同一时钟的控制下&#xff0c;同步传输数据。 异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。 二、UART 通用异步收发传输器&#xff08;Unive…

【Vue/element】 el-table实现表格动态新增/插入/删除 表格行,可编辑单元格

el-table实现表格动态新增/插入/删除 表格行&#xff0c;可编辑单元格 效果如下&#xff1a; 点击“新增一行”可以在表格最后新增一行&#xff0c;单元格内容可编辑 点击绿色按钮&#xff0c;可在指定行的后面插入一行 点击红色-按钮&#xff0c;可以删除指定行 原理&#…

让小程序动起来-轮播图的两种方式--【浅入深出系列003】

浅入深出系列总目录在000集 如何0元学微信小程序–【浅入深出系列000】 文章目录 本系列校训学习资源的选择啥是轮播图轮播图的关键代码最常见的轮播图代码便于理解的轮播代码两种轮播代码的比较 实际操练第一步&#xff0c;就是找到文件。第二步&#xff0c;先改动一下最显眼…

Docker使用总结

Docker 1.什么是 Docker 官网的介绍是“Docker is the world’s leading software container platform.” 官方给Docker的定位是一个应用容器平台。 Docker 是一个容器平台的领导者 Docker 容器平台 Docker 应用容器平台 application项目 Mysql Redis MongoDB ElasticSeacrh …

分布式运用——存储系统Ceph

分布式运用——存储系统Ceph 一、Ceph 介绍1.Ceph 简介2、存储基础2.1 单机存储设备2.2 单机存储的问题2.3 商业存储解决方案2.4 分布式存储&#xff08;软件定义的存储 SDS&#xff09;2.5 分布式存储的类型 3.Ceph 优势3.1 高扩展性3.2 高可靠性3.3 高性能3.4 功能强大 4.Cep…

hybridCLR热更遇到问题

报错1&#xff1a; No ‘git‘ executable was found. Please install Git on your system then restart 下载Git安装&#xff1a; Git - Downloading Package 配置&#xff1a;https://blog.csdn.net/baidu_38246836/article/details/106812067 重启电脑 unity&#xff1a;…

嵌入式工程师常用的软件工具推荐

前言&#xff1a;常言道&#xff1a;工欲善其事&#xff0c;必先利其器。作为一名合格的嵌入式工程师&#xff0c;日常可能需要接触和处理各种奇奇怪怪的问题&#xff0c;这时候一款高适配性的工具将会令工作效率大大提升。作者根据个人的实际使用情况与粉丝的客观感受&#xf…

MySQL表的约束

目录 前言 1.什么是约束 2.空属性 3.默认值 4.列描述 5.zerofill 6.主键 7.自增长 8.唯一键 9.外键 总结 前言 hello&#xff0c;各位小伙伴大家好&#xff0c;本章内容为大家介绍关于MySQL约束的相关内容&#xff0c;关于约束这个概念&#xff0c;如果是第一次接触可…

JAVA ---- 经典排序算法

目录 一. 插入排序 1. 直接插入排序 代码演示 2.希尔排序( 缩小增量排序 ) 二. 选择排序 1.直接选择排序 代码&#xff1a; 2. 堆排序 代码 三. 交换排序 1. 冒泡排序 代码 2. 快速排序 代码&#xff08;有注释&#xff09;&#xff1a; 动图来自网…

ubuntu创建多用户并使用ssh链接

添加多个同时登录的用户 以下内容中的“username”根据自己需求自己定义 1.创建新用户 sudo useradd username2.给新用户添加管理权限 sudo vim /etc/sudoers打开的文件中添加如下内容 username ALL(ALL:ALL) ALL3.设置密码 输入&#xff1a; sudo passwd username打开的…

「软件测试」最全面试问题和回答,全文背熟不拿下offer算我输

一般要应聘关于测试的工作&#xff0c;面试题会不会很难?下面小编整理了软件测试面试题及答案&#xff0c;欢迎参考! 一、引言 1.1 文档目的 本次文档是为了收集在面试中遇到的一问题与常见的一些答案并不是唯一答案 二、职业规划 2.1 简单的自我介绍下 面试宫&#xff…

点大商城V2_2.5.0 全开源版 商家自营+多商户入驻 百度+支付宝+QQ+头条+小程序端+unipp开源前端安装测试教程

播播资源安装点大商城V2_2.5.0 全开源版测试后发现后台总体体验下来比较简洁&#xff0c;营销功能还是挺多该有的都有了&#xff0c;相比上一版优化很多细节。首页和会员中心均支持DIY装修&#xff0c;底部菜单也一样&#xff0c;安装测试中目前未发现BUG&#xff0c;小程序整体…

etcd实现大规模服务治理应用实战

导读&#xff1a;服务治理目前越来越被企业建设所重视&#xff0c;特别现在云原生&#xff0c;微服务等各种技术被更多的企业所应用&#xff0c;本文内容是百度小程序团队基于大模型服务治理实战经验的一些总结&#xff0c;同时结合当前较火的分布式开源kv产品etcd&#xff0c;…

文献阅读笔记——求解车辆路径问题及其变体的元启发式算法的分类综述

论文题目&#xff1a;A taxonomic review of metaheuristic algorithms for solving the vehicle routing problem and its variants 其他信息&#xff1a;Computers & Industrial Engineering|2020|Raafat Elshaer⁎, Hadeer Awad 文章贡献&#xff1a;1&#xff09;对使…