『C++成长记』构造函数和析构函数

news2024/9/21 0:46:38

🔥博客主页:小王又困了

📚系列专栏:C++

🌟人之为学,不日近则日退 

❤️感谢大家点赞👍收藏⭐评论✍️


目录

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

📒1.1认识默认成员函数 

二、构造函数

📒2.1为什么要有构造函数

📒2.2构造函数的概念

📒2.3构造函数的特性

📒2.4编译器生成的构造函数 

📒2.5编译器生成构造函数的作用 

📒2.6默认构造函数

三、析构函数

📒3.1析构函数的概念

📒3.2析构函数的特性

📒3.3编译器生成析构函数的作用


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

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

空类不是没有任何用,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

📒1.1认识默认成员函数 

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

  • 构造函数:完成初始化工作。
  • 析构函数:完成对空间的清理工作。
  • 拷贝构造:使用同类对象初始化创建对象。
  • 赋值重载:把一个对象赋值给另外一个对象。
  • 取地址重载:普通对象和const对象取地址,这两个很少自己实现。

二、构造函数

📒2.1为什么要有构造函数

class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    d1.Init(2022, 7, 5);//调用初始化函数
    return 0;
}

     以前我们创建对象后,都要自己调用初始化函数,这样的操作十分麻烦,而且当对象增多时,有些对象我们可能会忘记初始化,这时程序就会出现错误。那么能否在创建对象的时候,就自动对它初始化。于是,就有了构造函数。

📒2.2构造函数的概念

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

class Date
{
public:
    //构造函数
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
 };
  
void TestDate()
{
   Date d1(2015, 1, 1); // 自己调用构造函数
}

📒2.3构造函数的特性

     构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。 

📝特性:

  •  函数名与类名相同。
  •  无返回值。
  •  对象实例化时编译器自动调用对应的构造函数。
  •  构造函数可以重载。
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();//错误写法
}

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

📒2.4编译器生成的构造函数 

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

class Date
{
public:
    /*
    // 如果用户显式定义了构造函数,编译器将不再生成
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    */
 
 private:
    int _year;
    int _month;
    int _day;
};
 
int main()
{
	Date d1;
	return 0;
}

     将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数。 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再 生成默认构造函数,Date d1; 没有可以调用的无参构造函数,所以会失败。 

📒2.5编译器生成构造函数的作用 

 

      d1对象调用了编译器生成的默认构造函数,但是对象_year_month_day,是随机值。那这里编译器生成的默认构造函数有什么用呢?

解答: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;
}

     如上代码 ,定义了一个日期类Date,有四个成员变量,其中_year、_month、_day都是内置类型,_t 是自定义类型,它是一个时间类Time,Time类中写了一个构造函数。运行程序,自定义类型调用了自己的默认构造函数,对值进行了初始化。这意味着,在创建对象的时候,会去使用编译器生成的无参默认构造函数。

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

🎀示例: 

class Date
{
private:
    int _year = 2023;
    int _month = 11;
    int _day = 16;
};
 
int main()
{
	Date d1;
	return 0;
}

📒2.6默认构造函数

     编译器自动生成的构造函数无参构造函数全缺省构造函数,这三种都叫做默认构造函数,它们都有一个共同的特点:可以不用传参。默认构造函数只能有一个,后面俩,在语法上可以构成函数重载,但是在无参调用的时候,会发生歧义,出现调用不明确。

//无参构造函数
Date()
{
    _year = 2023;
    _month = 11;
    _day = 16;
}

//全缺省构造函数
Date(int year = 2023, int month = 11, int day = 16)
{
    _year = year;
    _month = month;
    _day = day;
}

注意:要把默认构造函数和默认成员函数区分清楚,默认成员函数是我们不写编译器会自动生成的默认构造函数是不需要传参的构造函数编译器生成的构造函数,既是默认构造函数,同时也是默认成员函数。 

三、析构函数

📒3.1析构函数的概念

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

📒3.2析构函数的特性

📝特性:

  •  析构函数名是在类名前加上字符 ~
  •  无参数无返回值类型。
  •  一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  •  对象生命周期结束时,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中的成员变量_array是在堆区上申请的空间,这块空间在程序结束后不会自动还给操作系统,当_array清理后,就找不到动态申请的那块空间,会造成内存泄漏,因此在对象销毁前,要通过析构函数去释放成员变量_array指向的空间,这就是析构函数的作用。

注意:析构函数不能重载

📒3.3编译器生成析构函数的作用

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

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三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在 d 销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。但是: main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁。

📝总结:

    一般情况下,有动态申请资源,就需要显式的写析构函数来释放资源,比如Stack类。没有动态申请的资源,可以不写析构函数,直接使用编译器生成的默认析构函数,比如 Date类。需要释放资源的成员都是自定义类型,也不需要写析构函数。


🎁结语: 

     本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。你们的支持就是博主最大的动力。

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

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

相关文章

【Linux】SELinux 关闭

SELinux 最在安装国产数据库&#xff0c;遇到了无法远程访问的问题&#xff0c;定位了之后&#xff0c;需要关闭SELinux 。 在关闭它之前我们一起了解一下什么是SELinux &#xff1f; 什么是SELinux 安全增强式 Linux&#xff08;SELinux&#xff09;是一种强制访问控制的…

ElementPlusError: [ElPagination] 你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档

使用element table出现这个错误好几回了&#xff0c;今天把它记录一下&#xff0c;并把错误原因复盘一遍。具体如下&#xff1a; 错误截图 原因 其实这个错误挺迷的&#xff0c;我把各种情况都测试了一遍&#xff0c;最后发现是因为给 翻页参数 total 传值错误导致的。 总结…

docker读取字体异常

解决方法 docker容器中执行 apk add ttf-freefont 根据版本不同 apk add ttf-dejavu-fonts apk add ttf-bernoulli

python 制作3d立体隐藏图

生成文件的3d图&#xff0c;例子&#xff1a; 文字&#xff1a; 隐藏图&#xff1a; 使用建议&#xff1a; &#xff11;、建议不用中文&#xff0c;因为中文太复杂&#xff0c;生成立体图效果不好。 &#xff12;、需要指定FONT_PATH&#xff0c;为一个ttf文件&#xff0c;…

Find My戒指|苹果Find My技术与戒指结合,智能防丢,全球定位

戒指是一种戴套在手指上做纪念或装饰用的小环&#xff0c;用金属、玉石等制成。如今智能戒指是炙手可热的可穿戴设备&#xff0c;智能戒指可以进行健康监测&#xff0c;包括实时监测心率、睡眠质量、步数等个人健康指标&#xff0c;并提供有关饮食和锻炼的建议&#xff0c;以帮…

自动化接口测试:Pytest让你轻松搞定!了解一般流程及方法

首先我们要明确&#xff0c;通常所接口测试其实就属于功能测试&#xff0c;主要校验接口是否实现预定的功能&#xff0c;虽然有些情况下可能还需要对接口进行性能测试、安全性测试。 在学习接口自动化测试之前&#xff0c;我们先来了解手工接口测试怎样进行。 URL组成 为了更…

代码随想录算法训练营 ---第五十一天

1.第一题&#xff1a; 简介&#xff1a; 本题相较于前几题状态复杂了起来&#xff0c;因为多了一个冷冻期。本题讲解可去代码随想录看&#xff0c;这里差不多只是加了些自己的理解。 动规五部曲&#xff0c;分析如下&#xff1a; 确定dp数组以及下标的含义 dp[i][j]&#x…

html5各行各业官网模板源码下载(1)

文章目录 1.来源2.源码模板2.1 HTML5白色简洁设计师网站模板 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134682321 html5各行各业官网模板源码下载&#xff0c;这个主题覆盖各行业的html官网模板&#xff0c;效果模…

用本子堆经验,手把手教你怎么写国自然项目基金!

随着社会经济发展和科技进步&#xff0c;基金项目对创新性的要求越来越高。申请人需要提出独特且有前瞻性的研究问题&#xff0c;具备突破性的科学思路和方法。因此&#xff0c;基金项目申请往往需要进行跨学科的技术融合。申请人需要与不同领域结合&#xff0c;形成多学科交叉…

一键分发平台-账号设置

首页-账号管理 ●登录后点击箭头-账号设置 控制台-账号管理 ●进入控制台-个人中心-账号管理 ●账号管理-个人资料介绍 ●账号管理-修改密码 ●账号管理-通知设置 ●账号管理-上传设置 ●账号管理-账号设置 ●账号管理-登录日志

数据结构与算法复习笔记

1.数据结构基本概念 数据结构: 它是研究计算机数据间关系&#xff0c;包括数据的逻辑结构和存储结构及其操作。 数据&#xff08;Data&#xff09;&#xff1a;数据即信息的载体&#xff0c;是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。 数据元素&#xf…

小程序禁止二次转发分享私密消息动态消息

第一种用法&#xff1a;私密消息 私密消息&#xff1a;运营人员分享小程序到个人或群之后&#xff0c;该消息只能在被分享者或被分享群内打开&#xff0c;不可以二次转发。 用途&#xff1a;主要用于不希望目标客群外的人员看到的分享信息&#xff0c;比如带有较高金额活动的…

【开源视频联动物联网平台】帧率、码率和分辨率

帧率、码率和分辨率是视频和图像处理中的重要概念&#xff0c;它们直接影响到视频的带宽占用和显示效果。在进行视频项目时&#xff0c;根据应用需求对视频参数进行调整是必要的&#xff0c;因此了解这些参数的具体含义和指标是非常重要的。 在进行视频项目时&#xff0c;需要…

软件系统安全漏洞检测应该怎么做?靠谱的软件安全检测公司推荐

软件系统安全漏洞检测是指通过对软件系统进行全面的、系统化的评估&#xff0c;发现和解决其中可能存在的安全漏洞和隐患。这些安全漏洞可能会被不法分子利用&#xff0c;引发数据泄露、系统瘫痪、信息被篡改等安全问题&#xff0c;给企业造成严重的经济和声誉损失。那么软件系…

万户ezOFFICE wpsservlet任意文件上传漏洞复现

0x01 产品简介 万户OA ezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品&#xff0c;统一的基础管理平台&#xff0c;实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台&#xff0c;将外网信息…

【论文精读】HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face

HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face 前言Abstract1 Introduction2 Related Works3 HuggingGPT3.1 Task PlanningSpecification-based InstructionDemonstration-based Parsing 3.2 Model SelectionIn-context Task-model Assignment 3…

linux终端命令

comman [-options] [parameter] /主文件夹/视频 ls [-a -l -h] [Linux 路径] -a 全部文件显示 &#xff0c;因为有些是隐藏的文件 -l 以列表的形式展示内容&#xff0c;展示更加细节 -h 以易于阅读的形式&#xff0c;列出文件大小&#xff0c;如K、M、G 混合使用&#xff1a; l…

数据挖掘实战-基于word2vec的短文本情感分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

css新闻链接案例

利用html和css构建出新闻链接案例&#xff0c;使用渐变色做出背景色变化 background: linear-gradient(to bottom, rgb(137, 210, 251), rgb(238, 248, 254), white); 利用背景图片&#xff0c;调整位置完成 dd { height: 28px; line-height: 28px; background-image: url(./图…

网络周期间全球在线销售额飙升,提高排名是关键:7大策略速览

网络周期间&#xff08;11月23-27日&#xff09;&#xff0c;全球在线销售额增长6%&#xff0c;达到2980亿美元&#xff0c;其中美国销售额708亿美元&#xff0c;增长5%。增长主要由订单量推动&#xff0c;消费者需求首次增长&#xff0c;寻求低价和便利。人工智能支持的无缝和…