(C++类的初始化和清理)构造函数与析构函数

news2024/11/28 18:55:20

在这里插入图片描述

目录

  • 1. 类的六个默认成员函数
  • 2. 构造函数(Constructor)
    • 2.1 概念
    • 2.2 特性
  • 3. 析构函数(Destructor)
    • 3.1 概念
    • 3.2 特性

在这里插入图片描述

1. 类的六个默认成员函数

一个类中如果什么成员都没有,称为空类

class Date {};

但是这并不代表空类里面什么都没有,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

在这里插入图片描述

2. 构造函数(Constructor)

2.1 概念

对于以下的Data类,我们平常要通过手动给Init赋值,但是如果我们利用构造函数,就能在对象创建时,自动将信息设置进去。

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

构造函数是一个特殊的成员函数:
1️⃣名字与类名相同
2️⃣创建类类型对象时由编译器自动调用
3️⃣在对象整个生命周期内只调用一次
4️⃣保证每个数据成员都有 一个合适的初始值

2.2 特性

构造函数的主要作用是初始化对象,不是开空间创建对象
它有如下几个特征:
1️⃣函数名与类名相同(类名是 Date,构造函数名就是 Date)
2️⃣无返回值(因为不具有返回类型)
3️⃣对象实例化时自动调用相对应的构造函数
4️⃣构造函数可以重载
5️⃣无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

代码实现:
下面的代码只需要 Date d1,d2,就会自动调用构造,就能保证对象一定是被初始化过的

  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); // 调用带参的构造函数
  
      
      // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
      // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
      Date d3();//这是一个函数声明
 }

注意:通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明

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

这个自动生成的无参的默认构造函数有什么用呢?
在这里插入图片描述

解答:
编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。
C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类
型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型

#include <iostream>
using namespace std;
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;
}

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

class Date
{
private:
     // 基本类型(内置类型)
     int _year = 1998;
     int _month = 1;
     int _day = 1;
     // 自定义类型
     Time _t;
};

3. 析构函数(Destructor)

3.1 概念

学习了构造函数我们知道一个对象是从哪来的,那么一个对象是如何消失的呢?

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

3.2 特性

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

接下来我们用数据结构中的栈来作示例

#include <iostream>
using namespace std;
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);
}

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;
}
// 程序运行结束后输出:~Time()

为什么最后会调用Time_t的析构函数呢?
解答:
因为其他三个内置类型销毁时不需要内存清理,系统会自动回收。
而_t是Time类对象,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。
但是主函数中不能直接调用Time的析构函数,所以实际调用的是Data类的析构函数,即调用Data类的析构函数,在其内部再调用Time类的析构函数
结论:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数
在这里插入图片描述

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

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

相关文章

树状图PPT怎么做?用这个树状图制作软件轻松拿捏!

在我们的日常工作和学习中&#xff0c;PPT已经成为了我们常见的展示方式。 在制作PPT时&#xff0c;树状图PPT是非常重要和常用的一种&#xff0c;并且在商务、教育等领域都非常受欢迎。那么&#xff0c;究竟什么是树状图PPT&#xff0c;如何使用树状图制作软件来快速绘制树状…

肖sir__linux讲解(2.1)

linux命令 cp 复制命令 a、cp 原文件名称 新文 件名称&#xff08;不存在的文件&#xff09; 案例&#xff1a;cp a k 截图&#xff1a; b.cp 原文件名称 原有文 件名称&#xff08;存在的文件&#xff09; 案例:cp a b 截图&#xff1a; c、cp 指定路径复制 格式&#xff…

C#源代码生成器深入讲解二

在阅读本文前需掌握源代码生成器相关知识C#源代码生成器深入讲解一 C#源代码生成器深入讲解二—增量生成器 源代码生成器有个非常大的弊病&#xff0c;每次都会遍历所有的语法树来分析,这样就有个问题&#xff0c;每次可能只修改了很少一部分或者只有很少一部分的代码需要分析…

Linux使用Docker完整安装Superset3,同时解决please use superset_config.py to override it报错

文章目录 Docker安装Superset流程1. 首先获取镜像2. 生成SSL3. 创建Superset容器4. 更新数据库5. 测试访问Superset Docker安装Superset流程 1. 首先获取镜像 docker pull amancevice/superset2. 生成SSL 接下来我们运行一些额外的程序&#xff1a; openssl rand -base64 4…

每一天的努力,都会让远方变得更近——中国人民大学与加拿大女王大学金融硕士

在这个快速变化的时代&#xff0c;我们每个人都面临着各种挑战和机遇。要想在这个世界上获得成功和成就&#xff0c;就需要不断地努力和奋斗。因为只有不断地努力&#xff0c;我们才能够实现自己的梦想和目标&#xff0c;每一天的努力都会让远方变得更近。中国人民大学与加拿大…

STM32——STM32F103时钟解析(正点原子资料+HAL库代码分析)

文章目录 前言时钟树详解系统时钟配置系统时钟使能配置 前言 上次写系统时钟解析的时候说出一篇103的时钟解析&#xff0c;我就整理HAL库开发的正点的资料&#xff0c;给小白梳理&#xff0c;我也是小白&#xff0c;不做权威使用。 时钟树详解 在 STM32 中&#xff0c;有五个…

MATLAB与Excel的数据交互

准备阶段 clear all % 添加Excel函数 try Excel=actxGetRunningServer(Excel.Application); catch Excel=actxserver(Excel.application); end % 设置Excel可见 Excel.visible=1; 插入数据 % % 激活eSheet1 % eSheet1.Activate; % 或者 % Activate(eSheet1); % % 打开…

springboot使用MongoTemplate根据正则表达式查询日期数据

一、日期正则表达式测试 匹配HH:mm:ss正则表达式写法有很多列举两个 .(点)代表任意匹配 ^开头必须是跟着的 : 精确匹配,必须是: ([0-1]?[0-9]|2[0-3]).([0-5][0-9]).([0-5][0-9]) ^([0-1]?[0-9]|2[0-3]).([0-5][0-9]).([0-5][0-9])$ ([0-1]?[0-9]|2[0-3]):([0-5][0-9]):…

【机器学习9】前馈神经网络

深度前馈网络是一类网络模型的统称&#xff0c;主要包括多层感知机、 自编码器、限制玻尔兹曼机&#xff0c; 以及卷积神经网络等。 1 激活函数 激活函数及对应导函数图其它Sigmoid 导数 在z很大或很小时都会趋近于0&#xff0c; 造成梯度消失的现象Tanh 其导数在z很大或很小…

Python接口自动化(什么是接口、接口优势、类型)

简介 经常听别人说接口测试&#xff0c;接口测试自动化&#xff0c;但是你对接口&#xff0c;有多少了解和认识&#xff0c;知道什么是接口吗&#xff1f;它是用来做什么的&#xff0c;测试时候要注意什么&#xff1f;坦白的说&#xff0c;笔者之前也不是很清楚。接下来先看一下…

模拟实现一个Linux中的简单版shell

exec系列接口中的环境变量 在之前我们学习了exec系类函数的功能就是将一个程序替换成另外一个程序。 然后就会出现下面的问题&#xff1a; 首先父进程对应的环境变量的信息是从bash中来的&#xff0c;因为我们自己写的父进程在运行的时候首先就要成为bash的子进程。这里我们将…

解决计算机丢失msvcr71.dll问题,总结5种解决方法分享

由于各种原因&#xff0c;计算机在使用的过程中可能会出现一些问题&#xff0c;其中之一就是丢失msvcr71.dll文件。这个问题可能会导致计算机无法正常运行某些程序或功能&#xff0c;给我们的生活和工作带来困扰。那么&#xff0c;当我们遇到这个问题时&#xff0c;应该如何解决…

福利来了,运营素材免费下载

各位运营的小伙伴&#xff0c;是不是在日常工作中常常用到这种场景&#xff1a;公司要做一个活动&#xff0c;老板让你写一个活动SOP&#xff0c;但是没有过往经验&#xff0c;一时无从下手&#xff0c;老板又死催。 自己想了解拉新的办法&#xff0c;但是一时找不到资料&…

双十一快递业务量暴增,快递驿站视频智能监控方案保障快递业务顺利开展

一、背景分析 虽然刚刚过去的双十一电商购物狂潮结束&#xff0c;但是快递业务量仍处在高峰期。据数据统计&#xff0c;今年全国邮政快递企业在11月11日当天共揽收快递包裹6.39亿件&#xff0c;是平日业务量的1.87倍&#xff0c;同比增长15.76%。随着电商购物节的不断增多&…

【Qt之QWizardPage】使用

介绍 QWizardPage类是向导页面的基类。 QWizard表示一个向导。每个页面都是一个QWizardPage。当创建自己的向导时&#xff0c;可以直接使用QWizardPage&#xff0c;也可以子类化它以获得更多控制。 页面具有以下属性&#xff0c;由QWizard呈现&#xff1a;a title&#xff0c;…

易点易动库存管理系统:革新企业库存管理,降本增效

在快速变化的市场环境中&#xff0c;企业面临着库存管理的巨大挑战。传统的库存管理方式耗时耗力&#xff0c;且常常因为信息滞后、数据不精确而导致库存积压或短缺。易点易动库存管理系统&#xff08;以下简称“易点易动”&#xff09;的出现&#xff0c;标志着企业库存管理进…

前端性能优化的方式

文章目录 前言DNS 预解析存储使用 HTTP / 2.0预加载预渲染懒执行与懒加载文件优化webpack优化如何根据chrome的timing优化移动端优化后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端系列文章 &#x1f431;‍&#x1f453;博主在前端…

Linux进程之进程的状态简述

文章目录 1.百度搜索2.对进程状态的认识2.0创建状态2.1就绪状态2.2运行状态2.3阻塞状态2.4挂起状态 3.认识LinuxOS下的进程3.0进程状态的简述3.1了解R/S状态3.2D深度睡眠状态3.3信号/调试暂停状态3.4僵尸状态 1.百度搜索 2.对进程状态的认识 一个进程所具有的状态为操作系统的…

demo(三)eurekaribbonhystrix----服务降级熔断

一、介绍&#xff1a; 1、雪崩&#xff1a; 多个微服务之间调用的时候&#xff0c;假如微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其他的微服务&#xff0c;这就是所谓的"扇出"。如果扇出的链路上某个微服务的调用响应的时间过长或者不可用&am…

开发者的第一台服务器 ECS云服务器低至99元:新老同享

“阿里云始终围绕‘稳定、安全、性能、成本、弹性’的目标不断创新&#xff0c;为客户创造业务价值。”10月31日&#xff0c;杭州云栖大会上&#xff0c;阿里云弹性计算计算产品线负责人张献涛表示&#xff0c;通过持续的产品和技术创新&#xff0c;阿里云发布了HPC优化实例等多…