C++篇----构造函数和析构函数

article/2025/10/2 6:19:54

在很多时候,当写了初始化,动态开辟的,需要写销毁函数,写了销毁函数之后,但是却忘记了调用这些函数,忘记调用初始化函数还好,编译器会报错,但是如果是忘记调用销毁函数,那么编译器是不会报错,但是不能说这个程序就没错哦了,反而有很大的问题,存在内存泄漏的问题,如和解决这样问题?这也是本文重点。C++增加了类的6个默认成员函数,本文先分享构造函数和析构函数。
构造函数–主要完成初始化工作,
析构函数–主要完成清理工作

文章目录

  • 一、前言
  • 二、构造函数
  • 三、析构函数


一、前言

在很多时候,当写了初始化,动态开辟的,需要写销毁函数,写了销毁函数之后,但是却忘记了调用这些函数,忘记调用初始化函数还好,编译器会报错,但是如果是忘记调用销毁函数,那么编译器是不会报错,但是不能说这个程序就没错哦了,反而有很大的问题,存在内存泄漏的问题,如和解决这样问题?这也是本文重点。C++增加了类的6个默认成员函数,本文先分享构造函数和析构函数。

构造函数–主要完成初始化工作
析构函数–主要完成清理工作

二、构造函数

构造函数是特殊的成员函数,虽然它的名字叫构造函数,但是它的主要任务不是开空间创建对象,而是初始化对象
特性:
1、函数名和类名相同。 如:类名Stack,那么构造函数的函数,名也为Stack
2、无返回值(也不需要void)。
3、对象实例化编译器自动调用对应的构造函数。对象在定义之后就会调用它的默认构造函数
4、构造函数可以重载。(构造函数虽然没有返回值,但是可以有参数)
5、如果类中没有显式定义构造函数,则c++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器不再默认生成。

以日期类带大家了解

#include<iostream>
using namespace std;class Date
{
public:Date(int year=2022, int month=4, int day=24){_year = year;_month = month;_day = day;}void Print(){cout << _year << '-' << _month << '-' << _day << endl;}int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();return 0;
}

在这里插入图片描述

在对象定义之后并没有显式调用构造函数,但是在打印这个对象的时候却是有内容的,因为在对象定义时编译器自动调用它的默认构造函数,(默认构造函数是构造函数参数列表全缺省)
在这里插入图片描述
在这里插入图片描述
构造函数是没有返回值的,且它的函数名与类名相同,它还能有参数也可以没有参数
无参和参数列表全给缺省值这两个函数在同一个类中只能出现其中之一

构造函数支持重载
在这里插入图片描述
对重载构造函数的调用
在这里插入图片描述

当构造函数重载,一个构造函数无参数,一个构造函数参数列表全给缺省值,对象定义之后自动调用它的默认构造函数,编译器不知道调用谁,此时会发生调用歧义,所以得出,构造函数无参数和参数列表全给缺省值这两个在一个类中只能出现其中之一,一个出现另一个就不能出现。

构造函数参数列表全为缺省参数或者无参时,在对象定以之后会自动调用,那么如果构造函数参数列表不权威缺省参数或者不为缺省参数时,应当如何?

当构造函数参数列表不全是缺省值时

在这里插入图片描述
此时会显示d1这个对象并不存在默认构造函数,在定义之后不能自动调用它的构造函数了
那么在定义对象时就不能简简单单的定义了 而是对象+参数列表,此时编译器才会自动调用构造函数在这里插入图片描述
但是就算构造函数参数列表全为缺省参数或者无参,也不能像这样
在这里插入图片描述

此时编译器并不知道这个对象是声明还是定义

Data d1;//当构造函数参数列表全是缺省值时,编译器在对象实例化时才会默认自动调用构造函数,不然的话就需要对其传参
对象+参数列表,此时就会自动调用构造函数

构造函数:要么是无参、要么是全缺省、要么是没有显式写编译器会自动生成默认构造函数(不传参就可以调用的函数就是默认构造函数)

构造函数替代了Init(初始化),可以不用调用Init也对这个对象初始化了,这样也就解决了因没有调用初始化带来的错误,
构造函数是给对象初始化,在对象定义时自动调用

但是如果当类中没有定义构造函数时,应该如何处理?

编译器会自动生成构造函数,但是自动生成的构造函数,编译器并没用对类中的内置类型成员初始化
但是也有一些编译器会将其内置类型成员初始化为0,不过大多数是不会处理的

内置类型:(int/double/指针等等)
自定义类型:自己定义的/struct/class等等定义的类型

编译器自动生成构造函数也并不是什么都不做,当我们在类中,不显式写构造函数,编译器会默认生成构造函数,类中内置类型不做处理,自定义类型会调用它的默认构造函数

以日期类中字自定义一个栈对象来看

#include<iostream>
using namespace std;
class Stack
{
public:Stack(int capacity = 4){_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("malloc fail\n");return;}_top = 0;_capacity = capacity;cout << "_top" << ' ' << "_capacity" << endl;}int _capacity;int* _a;int _top;
};class Data
{
public:void Print(){cout << _year << '-' << _month << '-' << _day << endl;}int _year;int _month;int _day;Stack _st;
};int main()
{Data d1;d1.Print();return 0;
}

在这里插入图片描述

可以发现,自动生成了默认构造函数,这里类的内置类型成员被处理为0了,其实大多数编译器是不会对类的内置类型成员进行处理

当类中没有构造函数时,编译器会默认自动生成构造函数 但是并不会对类的内置类型成员做处理(初始化)
当类中有自定义类型成员时,编译器会默认自动调用自定义类型它的构造函数,
同时有些编译器也会将类的内置类型成员初始化为0,但是这只是有些编译器,并不是全部

那么哪种类可以让编译器默认自动生成构造函数哪些不能? 一般情况下,类只要有内置类型成员,理论上不能让编译器默认自动生成构造函数
一般情况下,如果类成员全是自定义类型成员,可以考虑让编译器默认自动生成构造函数(两个栈实现队列)

所以在c++11标准发布,也算是为其做了一些补丁
在类中内置类型成员在声明的时候给缺省值,此时编译器默认自动生成构造函数时
这些内置类型成员不再是随机值,而是这些缺省值

#include<iostream>
using namespace std;
class Stack
{
public:Stack(int capacity = 4){_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("malloc fail\n");return;}_top = 0;_capacity = capacity;cout << "_top" << ' ' << "_capacity" << endl;}int _capacity;int* _a;int _top;
};class Data
{
public:void Print(){cout << _year << '-' << _month << '-' << _day << endl;}//可以在声明时给其缺省值int _year = 1;int _month = 1;int _day = 1;Stack _st;
};int main()
{Data d1;d1.Print();return 0;
}

在这里插入图片描述

类中没有定义构造函数,编译器会自动生成默认构造函数,再自动调用生成的构造函数,然后此时对类的内置类型成员给缺省值,此时就相当于是对类的内置类型成员处理

  1. 类中没有显式定义构造函数,编译器会自动生成一个无参的默认构造函数
  2. 内置类型成员不做处理(a 有些编译器会处理 b.c++11标准对其缝补,声明可以给缺省值初始化)
  3. 自定义类型成员,会自动去调用它的构造函数

关于构造函数
总结:

  1. 一般情况下,构造函数都需要我们自己显式写
  2. 内置类型成员都有缺省值,且这些缺省值初始化符合自己要求,不用显式写构造函数
  3. 类中成员全是自定义类型,且这些类型都定义默认构造函数,不用显式写构造函数

三、析构函数

析构函数与构造函数功能相反,它是对资源的清理,相当于销毁函数,析构函数是在定义的对象生命周期结束时自动调用析构函数,完成对资源的清理,这样就算忘了调用销毁函数也不会造成内存泄漏了

析构函数特性:

  1. 析构函数名是在类名前加 ~
  2. 无参数,无返回值
  3. 一个类只能有一个析构函数(不能重载,析构函数无参数),
    若是未显式定义,系统会自动生成默认析构函数。
  4. 对象生命周期结束时,编译器会自动调用析构函数
    5.若是未显式定义,系统会自动生成默认析构函数(生成的默认析构函数和自动生成的构造函数类似(a.内置类型成员不做处理 b.自定义类型会调用它的析构函数))

以栈为例

#include<iostream>
using namespace std;
class Stack
{
public:Stack(int capacity = 4){_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("malloc fail\n");return;}_top = 0;_capacity = capacity;cout << "_top=" <<_top<< ' ' << "_capacity="<<_capacity << endl;}~Stack(){free(_a);_a = nullptr;_top = 0;_capacity = 0;cout << "_top=" << _top << ' ' << "_capacity=" << _capacity << endl;}int _capacity;int* _a;int _top;
};int main()
{Stack st1;return 0;
}

在这里插入图片描述
在这里插入图片描述

调试转到反汇编,可以发现,是在对象生命周期结束,自动调用析构函数
类中没有显式写析构函数,编译器会自动生成一个默认析构函数,其实和构造函数差不多

析构函数总结

一般情况下,如果对类成员写的是静态的,那么就不用写析构函数。有动态申请资源的,就需要显式写析构函数释放资源。

类中成员没有动态申请资源,不需要写析构函数
类中需要释放资源的成员都是自定义类型,不需要写析构函数


http://chatgpt.dhexx.cn/article/0S8pVIel.shtml

相关文章

c++构造函数和析构函数

一、构造函数和析构函数的特点 构造函数和析构函数是一种特殊的公有成员函数&#xff0c;每一个类都有一个默认的构造函数和析构函数&#xff1b;构造函数在类定义时由系统自动调用&#xff0c;析构函数在类被销毁时由系统自动调用&#xff1b;构造函数的名称和类名相同&#…

构造函数与析构函数

一&#xff0c;引言 由于c语言常常会忘记初始化与销毁&#xff0c;造成许多麻烦。所以c就引入了构造函数与析构函数&#xff0c;分别用来完成初始化与清理工作&#xff0c;且由编译器自动调用&#xff0c;这就避免了许多麻烦。 二&#xff0c;构造函数 构造函数是一个特殊的成…

构造函数和析构函数

文章目录 前言 1.构造函数<1>概念<2>特性 2.初始化列表<1>概念<2>特征 3.析构函数<1>概念<2.>特征 前言 如不清楚类的定义可以点击此篇文章&#xff1a;类的定义与引入 C为很么要引入构造函数和析构函数呢&#xff0c;前文讲到大佬引入了…

C++ 构造函数和析构函数 详解

目录 概述构造函数的分类1. 无参(默认)构造函数2. 有参构造函数3. 委托构造函数4. 复制(拷贝)构造函数5. 移动构造函数 构造函数调用规则析构函数 概述 C中用构造函数和析构函数来初始化和清理对象&#xff0c;这两个函数将会被编译器自动调用。对象的初始化和清理是非常重要的…

java异常处理及自定义异常

异常处理的实际上就是&#xff1a; 有风险的行为&#xff08;方法&#xff09;可能会将异常抛出&#xff08;throws&#xff09;。调用该方法的程序会尝试&#xff08;try&#xff09;去运行,运行的同时捕捉&#xff08;catch&#xff09;异常。 简而言之&#xff0c;就是对有…

java异常 — — 自定义异常

三、自定义异常 3.1、概述 为什么需要自定义异常类: Java中不同的异常类分别表示看某一种具体的异常情况&#xff0c;那么在开发中总是有些异常情况是SUN没有定义好的此时我们根据自己业务的异常情况来定义异常类。例如年龄负数问题&#xff0c;考试成绩负数问题等等。 在上…

JAVA自定义异常处理

自定义异常处理可以分为两种&#xff0c;一种是自定义编译处理&#xff0c;另一种是自定义运行处理 1.自定义编译处理需要创建一个异常类用于继承Exception类 重写构造器 在出现异常的地方用throw new 自定义对象抛出 作用&#xff1a;编译时异常时编译阶段就报错&#xff…

Java的自定义异常类

Java的异常处理机制可以让程序具有极好的容错性&#xff0c;让程序更加健壮。当程序运行出 现意外情形时&#xff0c;系统会自动生成一个 Exception对象来通知程序&#xff0c;从而实现将“业务功 能实现代码”和“错误处理代码”分离&#xff0c;提供更好的可读性。 Java把所…

Java自定义异常及统一处理,信息返回

开始操作 创建enums&#xff0c;exception包&#xff1a; enums包下&#xff1a; 创建BaseCodeEnum接口 创建Response类&#xff1a;为统一信息返回类 创建ResponseCode枚举类&#xff1a;在这里定义我们需要的异常 exception包下&#xff1a; 创建HandlerException类&#…

Java自定义异常类统一处理异常

当程序发生异常时&#xff0c;会返回一大堆不友好的内容&#xff0c;非常不美观&#xff01; 我们在写代码的时候&#xff0c;对异常处理一般是try catch或者抛出异常throws Exception。 try catch大家都知道&#xff0c;代码中大量的try catch会占用内存影响性能&#xff0c…

Java中的自定义异常

代码实现 自定义异常类型主要实现代码 public class Exception_demo extends Exception{//自定义异常&#xff0c;需要把自定义异常类继承于Exception异常类&#xff0c;自定义异常类属于异常类的子类public Exception_demo(){//构造方法也叫做构造器&#xff0c;构造方法的名…

【Java异常】自定义异常

Java中定义了大量的异常类&#xff0c;虽然这些异常类可以描述编程时出现的大部分异常情况&#xff0c;但是在程序开发中有时可能需要描述程序中特有的异常情况,例如在设计divide()方法时不允许被除数为负数。为了解决这样的问题,Java允许用户自定义异常&#xff0c;但自定义的…

JAVA项目中自定义异常

JAVA项目中自定义异常 1.数据返回处理类 Data public class R<T> implements Serializable {private static final long serialVersionUID -8497670085742879369L;ApiModelProperty(value "返回码", example "200")private Integer code200;Api…

Java自定义异常理解

前言&#xff1a;看了许多博客和书&#xff0c;都对自定异常一笔带过&#xff0c;总让人感觉莫名奇妙&#xff0c;一直在问自己一个问题&#xff0c;我们能很好的解决异常就很不错了&#xff0c;为什么还要自己自定义异常&#xff0c;让自己去自找麻烦呢&#xff1f;后来我才理…

Java自定义异常

使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外&#xff0c;用户还可以自定义异常。用户自定义异常类&#xff0c;只需继承Excepition类即可 在程序当中自定义异常类&#xff0c;大体可以分成几个步骤&#xff1a; 1.创建自定义异常类 2.在方法中通过t…

JAVA 基础学习之异常机制

异常机制 1、概念 异常指程序运行过程中出现的非正常现象&#xff0c;例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。在Java的异常处理机制中&#xff0c;引进了很多用来描述和处理异常的类&#xff0c;称为异常类。 2、异常的分类 Throwable下面又派生…

【Java】自定义异常

自定义异常&#xff1a; java提供的异常类&#xff0c;不够我们使用&#xff0c;需要自己定义一些异常类 格式&#xff1a; public class XXException extends Exception|RuntimeException{ 添加一个空参数的构造方法 添加一个带异常信息的构造方法 } 注意&#xff1a; 1.自…

Java异常详解及自定义异常

我已经不用 try catch 处理异常了&#xff01;太烦人了_51CTO博客_try catch处理什么异常 一、异常的概念 1.定义&#xff08;什么是异常&#xff1f;&#xff09; 异常是例外&#xff0c;是一个程序在执行期间发生的事件&#xff0c;它中断正在执行程序的正常指令流。软件开发…

哈夫曼树(带权路径长度+树的带权路径长度+哈夫曼树定义+构造哈夫曼树+哈夫曼树性质+哈夫曼编码+计算平均码长-这里指WPL)

带权路径长度 树的带权路径长度WPL 哈夫曼树 哈夫曼树构造 哈夫曼树性质 哈夫曼编码 固定长度编码 可变长编码 前缀编码 固定长度编码、可变长编码、前缀编码、哈夫曼编码 思维倒图 试题

哈夫曼树——【实例】利用3,6,8,12,5,7这六个值作为叶子结点的权,由该权值集合构造的哈夫曼树中带权路径长度之和为多少,该树的深度为多少。

利用3&#xff0c;6&#xff0c;8&#xff0c;12&#xff0c;5&#xff0c;7这六个值作为叶子结点的权&#xff0c;由该权值集合构造的哈夫曼树中带权路径长度之和为多少&#xff0c;该树的深度为多少。 基础知识 哈夫曼树是一种带权路径长度最短的二叉树&#xff0c;也称为最优…