C++类与对象(2)—构造函数析构函数

目录

 一、类的6个默认成员函数

 二、构造函数

1、定义 

2、特征

 三、析构函数

1、定义

2、特征

 四、默认生成构造&析构

1、定义 

 2、内置类型

3、自定义类型 

4、声明处给默认值

5、总结 

下一篇


 一、类的6个默认成员函数

如果一个类中没有定义任何成员,我们可以称之为空类。

然而,实际上空类并不是真的什么都没有。当我们没有在类中显式定义任何成员时,编译器会自动生成以下6个默认成员函数:

这些默认成员函数在需要时会被编译器自动生成,以提供类的基本功能。尽管我们没有显式定义任何成员,但这些默认成员函数确保了类的完整性和正确性。

本次主要讲解前前两个默认成员函数。 

 二、构造函数

之前学习数据结构中的 “栈” 时,对其进行初始化的函数如下:

class Stack
{
public:void Init(int n){a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("malloc fail");return;}_capacity = n;_size = 0;}private:int* _a;int _size;int _capacity;
};
对于Stack类,可以通过 Init 公有方法给对象进行初始化,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?

这时,构造函数登场。 

1、定义 

  • 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次
  •  构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

2、特征

其特征如下:
  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。—多种构造方式

下面通过例子一一解释 :

构造函数可以重载。(本质可以写多个构造函数,提供多种初始化方式) 

class Stack
{
public:// 1.无参构造函数Stack(){_a = nullptr;_size = _capacity = 0;}// 2.带参构造函数Stack(int n){_a = (int*)malloc(sizeof(int) * n);if (_a == nullptr){perror("malloc fail");return;}_capacity = n;_size = 0;}private:int* _a;int _size;int _capacity;
};

 两个Stack函数都为构造函数,有无参数均可以,他们共同的特点是函数名与类名相等,无返回值,其余部分跟正常函数一样。

接下来看如何在主函数调用构造函数初始化对象。

当我们声明类的对象后,程序运行到这段代码后,编译器会自动调用无参数的构造函数进行初始化。 

int main()
{Stack st;return 0;
}

在下图中,我们对Stack st;打断点,在调试中可以看到按F11之后直接跳转到无参数的Stack()进行初始化。

 也可以选择选择带参数的构造函数进行初始化,只需在后面加上参数即可。

Stack st(4);

我们再看一个日期类:


class Date
{
public://Date()//{//	_year = 1;//	_month = 1;//	_day = 1;//}////Date(int year, int month, int day)//{//	_year = year;//	_month = month;//	_day = day;//}//缺省构造函数代替上述函数重载Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << _year << "年" << _month << "月" << _day << "日" << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(2023, 2, 3);d1.Print();d2.Print();return 0;
}

除了上述的两种构造函数,我们还可以结合缺省参数使其更完善,只需这一个构造函数就可满足各种情况,一般来说很多时候都喜欢使用全缺省或半缺省的构造函数。

注意:这种缺省构造函数不能与无参的构造函数同时存在,编译能通过但有警告,会产生歧义,程序不知道调用哪个。

 三、析构函数

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?

1、定义

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

2、特征

特征如下:

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

下面代码中的~Stack()即为析构函数:

class Stack
{
public:Stack(){cout << "Stack()" << endl;_a = nullptr;_size = _capacity = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_size = _capacity = 0;}private:int* _a;int _size;int _capacity;
};int main()
{Stack st;//Stack st(4);//st.Destroy();由析构函数代替return 0;
}

我们使用调试看一下程序如何调用 ~Stack()函数:

在return 0;位置打断点,按F11可以看到直接进入~Stack()函数

程序直接跳转~Stack()函数 

如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

 四、默认生成构造&析构

1、定义 

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

 2、内置类型

我们来看下面的例子: 
class Date
{
public:void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}private:int _year ;int _month ;int _day ;
};int main()
{Date d1;d1.Print();return 0;
}

 通过结果可知,实际上并没有对成员变量自动进行初始化。

如果我们加上自己定义的构造函数呢?
Date(int year = 0, int month = 1, int day = 1)
{_year = year;_month = month;_day = day;
}

结果可以正常初始化。

关于编译器生成的默认成员函数,很多人会有疑惑:不实现构造函数的情况下,编译器会
生成默认的构造函数。但是看起来默认构造函数又没什么用?对象调用了编译器生成的默认构造函数,但是d1对象_year/_month/_day,依旧是随机值。
也就说在这里编译器生成的默认构造函数并没有什么用??
解答
  1. C++规定:默认生成构造和析构函数对内置类型成员不做处理,内置类型就是语言提供的数据类型,如:int/char...。
  2. 自定义类型的成员,会去调用它的默认构造(不用传参数的构造),自定义类型就是我们使用class/struct/union等自己定义的类型。

3、自定义类型 

我们通过下面代码看一下自定义类型的默认函数:

下面是用栈实现队列的程序,使用两个栈模拟实现队列,编译器生成默认的构造函数会对自定类型成员MyQueue调用的它的默认成员函数。

class Stack
{
public:Stack(){_a = nullptr;_size = _capacity = 0;}private:int* _a;int _size;int _capacity;
};class MyQueue {
public:void push(int x) {}//....Stack _pushST;Stack _popST;
};int main()
{MyQueue q;return 0;
}

输出结果如下:(使用两个栈模拟实现队列,构造和析构函数各调用两次)

结论:

  • 默认生成构造函数,对自定义类型成员,会调用他的默认构造函数。
  • 默认生成析构函数,对自定义类型成员,会调用他的析构函数。

4、声明处给默认值

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

如下图所示: 

class Date
{
public:void Print(){cout << _year << "年" << _month << "月" << _day << "日" << endl;}private:int _year = 1;int _month = 1;int _day = 1;
};int main()
{Date d1;d1.Print();return 0;
}

 成功初始化:

 

我们对MyQueue函数中新增一个整型变量size。

class MyQueue {
public:void push(int x) {}//....Stack _pushST;Stack _popST;int _size;
};int main()
{MyQueue q;return 0;
}

 在调试中可以看到size未初始化,

这时可以在声明处给默认值0。 

int _size = 0;

可以看到size变量成功初始化。 

 

5、总结 

  • 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
  • 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数
  • 一般情况下,都需要我们自己写构造函数,决定初始化方式;成员变量全是自定义类型,可以考虑不写构造函数。

下一篇

C++类与对象(3)—拷贝构造函数&运算符重载

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

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

相关文章

Idea2023 Springboot web项目正常启动,页面展示404解决办法

Idea2023 Springboot web项目正常启动,页面展示404解决办法 问题&#xff1a; 项目启动成功&#xff0c;但是访问网页&#xff0c;提示一直提示重定向次数过多&#xff0c;404 解决方法 在IDEA的Run/Debug Configurations窗口下当前的Application模块的Working directory中添…

python 对图像进行聚类分析

import cv2 import numpy as np from sklearn.cluster import KMeans import time# 中文路径读取 def cv_imread(filePath, cv2_falgcv2.COLOR_BGR2RGB): cv_img cv2.imdecode(np.fromfile(filePath, dtypenp.uint8), cv2_falg) return cv_img# 自定义装饰器计算时间 def…

vue中使用echarts渐变柱状图 Cannot read properties of undefined (reading ‘graphic‘)解决方法

在使用渐变颜色时报错&#xff0c;Cannot read properties of undefined (reading ‘graphic’) echarts也下载了&#xff0c;引入了&#xff0c;就是报错&#xff0c;用不了new charts&#xff0c; 结果换了一个版本号就可以了&#xff0c;本来用的"echarts": "…

7.docker运行redis容器

1.准备redis的配置文件 从上一篇运行MySQL容器我们知道&#xff0c;需要给容器挂载数据卷&#xff0c;来持久化数据和配置&#xff0c;相应的redis也不例外。这里我们以redis6.0.8为例来实际说明下。 1.1 查找redis的配置文件redis.conf 下面这个网址有各种版本的配置文件供…

02-1解析xpath

我是在edge浏览器中安装的xpath&#xff0c;需要安装的朋友可以参考下面这篇博客最新版edge浏览器中安装xpath插件 一、xpathd的使用 安装lxml pip install lxml ‐i https://pypi.douban.com/simple导入lxml.etree from lxml import etreeetree.parse() 解析本地文件 htm…

linux镜像的下载,系统下载(个人使用)

文章目录 一、系统之家二、国内镜像源三、Centos官网四、安装成功截图五、镜像类型的区别参考文档 一、系统之家 系统之家官网 二、国内镜像源 下载镜像地址&#xff1a; 1、官网地址&#xff1a;https://www.centos.org/ 2、阿里镜像站&#xff1a;https://mirrors.aliyu…

java基础练习缺少项目?看这篇文章就够了(上)!

公众号&#xff1a;全干开发 。 专注分享简洁但高质量的动图技术文章&#xff01; 项目概述 本教程适合刚学习完java基础语法的同学&#xff0c;涉及if语句、循环语句、类的封装、集合等基础概念&#xff0c;使用大量gif图帮助读者演示代码操作、效果等&#xff0c;是一个非常…

基于单片机16路抢答器仿真系统

**单片机设计介绍&#xff0c; 基于单片机16路抢答器仿真系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的16路抢答器仿真系统是一种用于模拟和实现抢答竞赛的系统。该系统由硬件和软件两部分组成。 硬件方面&am…

CICD 持续集成与持续交付——gitlab

部署 虚拟机最小需求&#xff1a;4G内存 4核cpu 下载&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ 安装依赖性 [rootcicd1 ~]# yum install -y curl policycoreutils-python openssh-server perl[rootcicd1 ~]# yum install -y gitlab-ce-15.9.3-ce.0…

Idea 2023.2.5配置(插件、Maven等)

IDEA2023.2.5配置 一. 插件Alibaba Java Coding Guidelines plugin supportMaven HelperMyBatisXSonarLintTranslationVuesion Theme 二. 自定义创建live template&#xff0c;快速写代码三. 修改全局配置3.1 Maven配置3.1.1 安装MavenStep1. 下载Step2. 安装Step3. 创建系统环…

Linux常见命令手册

目录 文件命令 文件和目录命令 文件的权限命令 文件搜索命令 进程命令 查看进程命令 关闭进程命令 用户和群组命令 网络命令 firewall-cmd 网络应用命令 高级网络命令 网络测试命令 网络安全命令 网络配置命令 软件管理命令 系统信息命令 vi编辑器 关机命令…

【uniapp/uview1.x】u-upload 在 v-for 中的使用时, before-upload 如何传参

引入&#xff1a; 是这样一种情况&#xff0c;在接口获取数据之后&#xff0c;是一个数组列表&#xff0c;循环展示后&#xff0c;需要在每条数据中都要有图片上传&#xff0c;互不干扰。 分析&#xff1a; uview 官网中有说明&#xff0c;before-upload 是不加括号的&#xff…

.Net6 部署到IIS示例

基于FastEndpoints.Net6 框架部署到IIS 环境下载与安装IIS启用与配置访问网站 环境下载与安装 首先下载环境安装程序&#xff0c;如下图所示,根据系统位数选择x86或者x64进行下载安装,网址&#xff1a;Download .NET 6.0。 IIS启用与配置 启用IIS服务 打开控制面板&#xff…

FPC焊点剥离失效分析

一、案例背景 FPC在后续组装过程中&#xff0c;连接器发生脱落。在对同批次的样品进行推力测试后&#xff0c;发现连接器推力有偏小的现象。据此进行失效分析&#xff0c;明确FPC连接器脱落原因。 #1、#2样品连接器脱落连接器脱落&#xff1b;#3样品连接器未脱落&#xff1b;…

邮箱设置第三方登录授权码获取

以QQ邮箱为例 QQ邮箱设置——账户 开启POP3/SMTP服务——完成验证后获得授权码&#xff0c;保存授权码

UE 视差材质 学习笔记

视差材质节点&#xff1a; 第一个是高度图&#xff0c; Heightmap Channel就是高度图的灰色通道&#xff0c;在RGBA哪个上面&#xff0c;例如在R上就连接(1,0,0,0)&#xff0c;G上就连接&#xff08;0,1,0,0&#xff09;逐次类推 去看看对比效果&#xff1a; 这个是有视差效果…

【windows 清理redis 缓存】

redis-cli.exe flushall flushdb

Linux下快速确定目标服务器支持哪些协议和密码套件

实现原理是利用TLS协议的特点和握手过程来进行测试和解析响应来确定目标服务器支持哪些TLS协议和密码套件。 在TLS握手过程中&#xff0c;客户端和服务器会协商并使用相同的TLS协议版本和密码套件来进行通信。通过发送特定的握手请求并分析响应&#xff0c;可以确定目标服务器…

制作Go程序的Docker容器(以及容器和主机的网络问题)

今天突然遇到需要将 Go 程序制作成 Docker 的需求&#xff0c;所以进行了一些研究。方法很简单&#xff0c;但是官方文档和教程有些需要注意的地方&#xff0c;所以写本文进行记录。 源程序 首先介绍一下示例程序&#xff0c;示例程序是一个 HTTP 服务器&#xff0c;会显示si…

FSOD论文阅读 - 基于卷积和注意力机制的小样本目标检测

来源:知网 标题:基于卷积和注意力机制的小样本目标检测 作者:郭永红&#xff0c;牛海涛&#xff0c;史超&#xff0c;郭铖 郭永红&#xff0c;牛海涛&#xff0c;史超&#xff0c;郭铖&#xff0e;基于卷积和注意力机制的小样本目标检测 [J/OL]&#xff0e;兵工学报. https://…