【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类生成的默认析构函数
// 注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数

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

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

相关文章

全波形反演培训的思考与总结

一. InversionNet 最简单的端到端DL_FWI 1. 网络结构&#xff1a; 图1 构建了一个具有编码器-解码器结构的卷积神经网络&#xff0c;根据地震波动数据模拟地下速度结构。编码器主要由卷积层构建&#xff0c;它从输入地震数据中提取高级特征并将其压缩为单个高维向量。解码器然后…

谷歌云:下一代开发者和企业解决方案的强力竞争者

自从2018年Oracle前研发总裁Thomas Kurian加入谷歌云&#xff08;Google Cloud&#xff09;并出任谷歌云CEO以来&#xff0c;业界对于谷歌云的发展就十分好奇。而谷歌云的前任CEO Diane Greene曾是VMware的创始人之一&#xff0c;那么两任企业级技术和解决方案出身的CEO&#x…

代码随想录算法训练营第五十五天 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

300.最长递增子序列 视频讲解&#xff1a;动态规划之子序列问题&#xff0c;元素不连续&#xff01;| LeetCode&#xff1a;300.最长递增子序列_哔哩哔哩_bilibili 代码随想录 &#xff08;1&#xff09;代码 674. 最长连续递增序列 视频讲解&#xff1a;动态规划之子序列问题…

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

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

Vue非单文件组件

组件就是用来实现局部特定功能效果的代码集合&#xff0c;为的就是复用编码&#xff0c;简化项目编码&#xff0c;提高运行效率。 组件分为非单文件组件和单文件组件&#xff0c;这里介绍的是非单文件组件。 一、创建组件 创建组件的语法格式如下&#xff1a; const 组件名 …

微信小程序开发之自定义组件(会议OA项目其他页面搭建)

目录 前言 一、WeChat中的自定义组件 1. 基本概述 2. 包含文件及作用 3. 自定义组件的作用 4.使用步骤&#xff1a; 二、tabs组件及会议管理布局 tabs组件 1. 创建组件 准备 创建 使用组件 会议管理布局 tabs.wxml指定组件模版 tabs.wxss完成样式设计 tabs.js定义属…

柔性数组的使用及注意事项

1.柔性数组在结构体当中,并且在结构体的最后面. 2.结构体中除了柔型数组外至少还要有一个其他成员. 3.sizeof()返回结构体的大小不包含柔性数组的大小. 4.malloc 例:struct sdshdr16 *p malloc(sizeof (struct sdshdr16) 32); // 32 为柔性数组的大小 5.free 例: fre…

讲解 CSS 过渡和动画 — transition/animation (很全面)

前言 由于用户越来越注重 Web应用 的使用体验&#xff0c;随之而来的是 Web应用 需要提供了更加完善的 Web 动画 效果来实现以平滑的状态贯穿于用户的整个使用过程中。现在&#xff0c;这已经是司空见惯了&#xff0c;用户潜意识是希望可以获得更快的反馈响应和更友好的用户界…

Python用selenium实现自动登录和下单的项目实战

本文主要介绍了Python用selenium实现自动登录和下单的项目实战&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧− 前言 学python对selenium应该不陌生吧 Selenium…

轻量级导出 Excel 标准格式

一般业务系统中都有导出到 Excel 功能&#xff0c;其实质就是把数据库里面一条条记录转换到 Excel 文件上。Java 常用的第三方类库有 Apache POI 和阿里巴巴开源的 EasyExcel 等。另外也有通过 Web 模板技术渲染 Excel 文件导出&#xff0c;这实质是 MVC 模式的延伸&#xff0c…

基于epoll封装非阻塞的reactor框架(附源码)

C++常用功能源码系列 文章目录 C++常用功能源码系列前言一、reactor架构二、client端reactor代码三、server端reactor代码四、单reactor架构可以实现百万并发总结前言 本文是C/C++常用功能代码封装专栏的导航贴。部分来源于实战项目中的部分功能提炼,希望能够达到你在自己的项…

Atlassian Confluence OGNL表达式注入RCE CVE-2021-26084

影响版本 All 4.x.x versions All 5.x.x versions All 6.0.x versions All 6.1.x versions All 6.2.x versions All 6.3.x versions All 6.4.x versions All 6.5.x versions All 6.6.x versions All 6.7.x versions All 6.8.x versions All 6.9.x versions All 6.1…

P1664 每日打卡心情好 题解

文章目录 题目背景题目描述输入格式输出格式样例样例输入样例输出 数据范围与提示思路及部分实现完整代码文章小结 题目背景 在洛谷中&#xff0c;打卡不只是一个简单的鼠标点击动作&#xff0c;通过每天在洛谷打卡&#xff0c;可以清晰地记录下自己在洛谷学习的足迹。通过每天…

Python数据挖掘实用案例——自动售货机销售数据分析与应用

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

瑞芯微RKNN开发·yolov5

官方预训练模型转换 下载yolov5-v6.0分支源码解压到本地&#xff0c;并配置基础运行环境。下载官方预训练模型 yolov5n.ptyolov5s.ptyolov5m.pt… 进入yolov5-6.0目录下&#xff0c;新建文件夹weights&#xff0c;并将步骤2中下载的权重文件放进去。修改models/yolo.py文件 …

汽车安全的未来:毫米波雷达在碰撞避免系统中的角色

随着科技的飞速发展&#xff0c;汽车安全系统变得愈加智能化&#xff0c;而毫米波雷达技术正是这一领域的亮点之一。本文将深入探讨毫米波雷达在汽车碰撞避免系统中的关键角色&#xff0c;以及其对未来汽车安全的影响。 随着城市交通的拥堵和驾驶环境的变化&#xff0c;汽车安全…

Cannot use object of type __PHP_Incomplete_Class as array

场景&#xff1a;将项目复制 出来一份后&#xff0c;修改控制器&#xff0c;打开后就报错 解决&#xff1a;将runtime 清除后就正常了

jenkins 原理篇——pipeline流水线 声明式语法详解

大家好&#xff0c;我是蓝胖子&#xff0c;相信大家平时项目中或多或少都有用到jenkins&#xff0c;它的piepeline模式能够对项目的发布流程进行编排&#xff0c;优化部署效率&#xff0c;减少错误的发生&#xff0c;如何去写一个pipeline脚本呢&#xff0c;今天我们就来简单看…

手写一个PrattParser基本运算解析器3: 基于Swift的PrattParser的项目概述

点击查看 基于Swift的PrattParser项目 PrattParser项目概述 前段时间一直想着手恶补 编译原理 的相关知识, 一开始打算直接读大学的 编译原理, 虽然内容丰富, 但是着实抽象难懂. 无意间看到B站的熊爷关于普拉特解析器相关内容, 感觉是一个非常好的切入点.所以就写了基于Swift版…

软考系列(系统架构师)- 2018年系统架构师软考案例分析考点

试题一 软件架构&#xff08;非功能性需求、C/S 架构&#xff09; 【问题1】&#xff08;8分&#xff09; 在系统架构设计中&#xff0c;决定系统架构设计的非功能性需求主要有四类&#xff1a;操作性需求、性能需求、安全性需求和文化需求。请简要说明四类需求的含义。 (1) …