当前位置: 首页 > news >正文

【C++】:类和对象(中)之类的默认成员函数——构造函数and析构函数

在这里插入图片描述

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

如果一个类中什么成员都没有,简称为空类
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数

class Date {};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于编译器的优化 我们未给_a赋值 这里是不会报错的
这里还需要强调一个点就是成员函数的地址不在对象中
成员变量存放在对象中

2. 构造函数

我们先来看两道经典的面试题
在这里插入图片描述
这道题首先排除A 因为nullptr属于运行错误 我们编译器在编译的时候只负责检查语法错误 nullptr语法是没错误的
这道题是正常运行的 但是为什么呢?
这是因为成员函数的地址不在对象中
成员变量存放在对象中
第二题
在这里插入图片描述
这里选择B运行崩溃
因为我们这里涉及到一个this指针的知识
this指针为nullptr 所以nullptr指向_a就会报错

2.1 概念

对于以下Date类:

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

对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

2.2 特性

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

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载
 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();}
  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
    代码演示和注释如下
class date
{
public:// 够成函数重载,但是无参调用存在歧义,不能同时存在/*date(){_year = 1;_month = 1;_day = 1;}*/date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//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;
};// date f(); 函数声明
int main()
{date d1;d1.print();date d2(2023, 10, 19);d2.print();date d3(2023, 10);d3.print();return 0;
}

在这里插入图片描述
6. 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??
解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数
大家可曾记得我前面的LeetCode刷题里面讲过一道题就是两个栈实现一个队列吗 我们构造函数现在就要用这道题来进行验证

class Date
{
public:// 够成函数重载,但是无参调用存在歧义,不能同时存在void Print(){cout << _year << "-" << _month << "-" << _day << endl;}// 默认生成的构造函数,啥事都干?// 处理自定义(会去调用这个成员的默认构造函数)// 内置类型不确定(看编译器),建议当成不处理
private:// C++11支持,声明时给缺省值int _year = 1;int _month = 1;int _day = 1;
};class Stack
{
public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_a = (int*)malloc(sizeof(int) * capacity);if (nullptr == _a){perror("malloc申请空间失败!!!");}_capacity = capacity;_top = 0;}private:int* _a;int _capacity;int _top;
};// 两个栈实现一个队列
class MyQueue
{
private:Stack _pushst;Stack _popst;int _size = 1;
};int main()
{Date d1;d1.Print();Stack st1;MyQueue mq;return 0;
}

在这里插入图片描述
那如果我将栈的初始化那部分注释掉了会发生什么呢?
在这里插入图片描述
注释掉了编译器不会默认去调用构造函数进行打印的 希望大家能够理解
这里再给大家强调一下 看图片解释
在这里插入图片描述
注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:// C++11支持,声明时给缺省值int _year = 1;int _month = 1;int _day = 1;
};// 1、我们不写编译默认生成那个构造函数,叫默认构造
// 2、无参构造函数也可以叫默认构造
// 3、全缺省也可以叫默认构造
// 可以不传参数就调用构造,都可以叫默认构造
// 这三个函数不能同时存在,只能存在一个int main()
{Date d1;d1.Print();return 0;
}
  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个
    注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数
class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
// 以下测试函数能通过编译吗?
void Test()
{Date d1;

3.析构函数

3.1 概念

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

3.2 特性

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){// Date严格来说,不需要写析构函数cout << "~Date()" << endl;}
private:// C++11支持,声明时给缺省值int _year = 1;int _month = 1;int _day = 1;
};
  1. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数
class Stack
{
public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_a = (int*)malloc(sizeof(int) * capacity);if (nullptr == _a){perror("malloc申请空间失败!!!");}_capacity = capacity;_top = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_capacity = _top = 0;_a = nullptr;}private:int* _a;int _capacity;int _top;
};class MyQueue
{// 默认生成析构函数,行为跟构造类似// 内置类型成员不做处理// 自定义类型成员会去调用他的析构
private:Stack _pushst;Stack _popst;int _size = 1;
};
int main()
{//Date d1;//Stack st1;MyQueue mq;return 0;
}
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()
// 在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数?
// 因为:main方法中创建了Date对象d,而d中包含4个成员变量,其中_year, _month, _day三个是
// 内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。但是:main函数
// 中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函
// 数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time
// 类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁
// main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数
// 注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数

相关文章:

【C++】:类和对象(中)之类的默认成员函数——构造函数and析构函数

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生成…...

sqlserver系统存储过程添加用户学习

sqlserver有一个系统存储过程sp_adduser&#xff1b;从名字看是添加用户的&#xff1b;操作一下&#xff0c; 从错误提示看还需要先添加一个登录名&#xff0c;再执行一个系统过程sp_addlogin看一下&#xff0c; 执行完之后看一下&#xff0c;安全性-登录名下面有了rabbit&…...

Monocle 3 | 太牛了!单细胞必学R包!~(一)(预处理与降维聚类)

1写在前面 忙碌的一周结束了&#xff0c;终于迎来周末了。&#x1fae0; 这周的手术真的是做到崩溃&#xff0c;2天的手术都过点了。&#x1fae0; 真的希望有时间静下来思考一下。&#x1fae0; 最近的教程可能会陆续写一下Monocle 3&#xff0c;炙手可热啊&#xff0c;欢迎大…...

基于VCO的OTA稳定性分析的零交叉时差模型研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

大数据Hadoop之——部署hadoop+hive+Mysql环境(window11)

一、安装JDK8 【温馨提示】对应后面安装的hadoop和hive版本&#xff0c;这里使用jdk8&#xff0c;这里不要用其他jdk了&#xff0c;可能会出现一些其他问题。 1&#xff09;JDK下载地址 Java Downloads | Oracle 按正常下载是需要先登录的&#xff0c;这里提供一个不用登录下载…...

app爬虫中的Airtest元素存在或等待

app爬虫中的Airtest元素存在或等待 一. poco等待 等待无错误 等待元素10秒。如果它没有出现&#xff0c;则不会引发任何错误。 poco(xxx).wait(timeout10)您还可以在.wait()之后执行一些操作&#xff0c;如click或long_click poco(xxx).wait(timeout10).click() poco(xxx).…...

Flink学习之旅:(三)Flink源算子(数据源)

1.Flink数据源 Flink可以从各种数据源获取数据&#xff0c;然后构建DataStream 进行处理转换。source就是整个数据处理程序的输入端。 数据集合数据文件Socket数据kafka数据自定义Source 2.案例 2.1.从集合中获取数据 创建 FlinkSource_List 类&#xff0c;再创建个 Student 类…...

SQL INSERT INTO 语句(在表中插入)

SQL INSERT INTO 语句 INSERT INTO 语句用于向表中插入新的数据行。 SQL INSERT INTO 语法 INSERT INTO 语句可以用两种形式编写。  第一个表单没有指定要插入数据的列的名称&#xff0c;只提供要插入的值&#xff0c;即可添加一行新的数据&#xff1a; INSERT INTO table_n…...

2023年最佳项目管理软件排行榜揭晓!

根据网络数据调查结果显示&#xff0c;今年有77%的组织将效率列为优先事项&#xff0c;而82%的领导人确认投资于新的项目管理和工作管理方案以提高效能。然而随着对价值的重新关注&#xff0c;选择适合的工程项目管理软件变得比以往任何时候都更加重要。好消息是通过对39个主要…...

华为OD DNA序列(100分)【java】A卷+B卷

华为OD统一考试A卷B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目&#xff0c;A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载&#xff0c;请点击以下链接进入&#xff…...

idea2023配置maven

看过【黑马程序员Maven全套教程&#xff0c;maven项目管理从基础到高级&#xff0c;Java项目开发必会管理工具maven】https://www.bilibili.com/video/BV1Ah411S7ZE?p9&vd_sourceedf9d91e5a0a27db51e3d6d4b9400637 配置的&#xff0c;前提要素配置也在这个课程里有啦&…...

Python 文件打包成可执行文件

打包 要将Python脚本打包成可执行文件&#xff0c;常见的做法是使用PyInstaller或cx_Freeze工具。下面是使用PyInstaller的基本步骤&#xff1a; 使用conda安装pyinstaller &#xff08;建议&#xff09; conda install -c conda-forge pyinstaller上面的命令从conda-forge通…...

14-bean创建流程5-初始化和循环依赖

文章目录 1.初始化和循环依赖1.1 初始化步骤1.2 循环依赖问题的产生1.3 如何解决循环依赖问题1.4 解决循环依赖二级缓存即可完成,为什么需要三级缓存1.5循环依赖有时报错1.初始化和循环依赖 1.1 初始化步骤 填充属性执行Aware执行BeanPostProcessor的postProcessBeforeInitia…...

drawio模板以及示例

drawio都能做那些事情和模板示例 你可以使用drawio&#xff0c;并使用drawio提供的扩展模板库和大量的形状库&#xff0c;针对很多不同的工业领域创建不同类型的图表。 针对如下的内容中的所有的图&#xff0c;均可以下载源文件并导入到drawio中再次编辑&#xff08;供学习者…...

YOLOv8改进实战 | 更换主干网络Backbone(四)之轻量化模型MobileNetV3

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…...

22-数据结构-内部排序-选择排序

简介&#xff1a;每一趟选择最小或最大的一个&#xff0c;排在前面或后面。主要右简单选择排序和堆排序 一、简单选择排序 1.1简介&#xff1a; 每趟选择最小的&#xff0c;放在前面&#xff0c;一次类推&#xff0c;代码思想&#xff1a;两个循环&#xff0c;外循环是趟数&a…...

utf8和utf8mb4字符集

柠檬(图片)派 有个玩家取了个名字&#xff0c;名字里带柠檬的图片。在发邮件的时候&#xff0c;要把玩家名字拼装成json格式&#xff0c;存储在mysql表中。 C代码和python代码处理都是正常的&#xff0c;但是调用pymysql的接口&#xff0c;执行sql写入到mysql时。 pymysql会报错…...

前端学成在线项目详细解析一

学成在线项目 01-项目目录 网站根目录是指存放网站的第一层文件夹&#xff0c;内部包含当前网站的所有素材&#xff0c;包含 HTML、CSS、图片、JavaScript等等。 首页引入CSS文件 <!-- 顺序要求&#xff1a;先清除再设置 --> <link rel"stylesheet" hre…...

Redis之UV统计

HyperLogLog 首先我们搞懂两个概念&#xff1a; UV&#xff1a;全称Unique Visitor&#xff0c;也叫独立访客量&#xff0c;是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站&#xff0c;只记录1次。PV&#xff1a;全称Page View&#xff0c;也叫页…...

sqlserver数据库,创建作业,定时执行sql

1 在业务中涉及到定时操作数据表时&#xff0c;可以设置定时作业。先创建一个存储过程&#xff0c;实现要定时执行的业务。 USE [MyDB] go create procedure [PROC_MYPROCEDURE] name varchar(50), score int, remark varchar(50) AS BEGIN insert into [mytable] values (n…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...