【C++基础(六)】类和对象(中) --构造,析构函数

news2024/12/25 12:34:39

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++初阶之路⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

类和对象-中

  • 1. 前言
  • 2. 构造函数
  • 3. 构造函数的特性
  • 4. 对默认构造函数的理解
  • 5. 对默认构造函数的补充
  • 6. 析构函数
  • 7. 对析构函数的理解
  • 8. 对默认析构函数的理解
  • 9. 总结以及拓展

1. 前言

本章重点:

本篇文章着重讲解类中的
两个默认函数,分别为:
构造函数,析构函数
并且介绍类的六个默认函数
(其他三个在后面章节讲解)

我们平时写数据结构时,比如:栈和队列

经常忘记写或者调用初始化函数
使得栈类中的变量是随机值,易出错

有时忘记调用销毁函数,导致内存泄漏
非常的不方便,不好用!

在这里插入图片描述

于是C++引入了这几个函数
可以有效的解决这些问题!


2. 构造函数

构造函数,顾名思义是用于初始化的函数

特性:

  • 函数名与类名相同
  • 无返回值
  • 对象实例化时自动调用对应的构造函数
  • 构造函数可以重载

需要注意的点:

  • 构造函数是特殊的成员函数
    不能将它与普通函数对比

  • 构造函数的任务是初始化对象
    而不是开辟空间创造对象

举例说明:

 class Date
 {
 public:
	  Date(int year, int month, int day)//构造函数
	  {
	       _year = year;
	       _month = month;
	       _day = day;
	  }
	  Date()//无参的构造函数
	  {
	  	_year = 1900;
	  	_month = 1;
	  	_day = 1;
	  }
 private:
      int _year;
      int _month;
      int _day;
 };

int main()
{
	 Date d1; // 调用无参构造函数
	 Date d2(2023, 7, 24);//调用含参的构造
}

注:构造函数是实例化对象时就调用

对象后面跟一个括号来调用!


3. 构造函数的特性

如果使用者没有显示写构造函数
系统就会自动生成一个默认构造函数

比如:

class Date
 {
  public:
 /*
 // 如果用户显式定义了构造函数,编译器将不再生成
 Date(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类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数
 
 // 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成
 
 // 无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用
 
 Date d1;
 return 0;
 }

对代码的解释:

屏蔽掉自己写的构造函数时
编译器会自动生成一个,d1在
实例化时就会去调用编译器生成的

然而当放开自己写的构造函数后
会报错,因为自己实现的构造函数
没有缺省值,并且d1实例化时没有传参


4. 对默认构造函数的理解

可能你们会疑惑:
既然编译器会自己生成构造函数
那我是不是写不写构造函数都可以了?

带着此疑问引出一个新概念:

内置类型和自定义类型

  • 内置类型是C++语言提供的类型
    比如: int/char类型

  • 自定义类型是用户使用class类
    定义出来的类型,如:Date类(日期类)

这个新概念有什么用?

  • 编译器自动生成的构造函数
    不会处理内置类型,它们是随机值

  • 然而自动生成的构造会处理自定义类型
    它会去调用自定义类型的默认构造

举例说明:

class Time
{
public:
	 Time()//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;
};

对代码的理解:

Date类没有显示写构造函数
所以编译器会自动生成一个构造函数
此构造函数不会处理内置类型
所以成员变量:
year,month,day都是随机值

然而此构造函数会处理自定义类型
它会去调用Time类的默认构造函数
将成员变量_t初始化


5. 对默认构造函数的补充

你可能会疑惑:上面的代码中
Time类显示写了构造函数
为啥还能被称为默认构造函数被调用?

默认构造函数可以是下面的类别:

  1. 编译器自动生成的默认构造
  2. 显示写的无参的构造函数
  3. 显示写的全缺省的构造函数

请看下面的代码:

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

上面两种写法都是默认构造函数!
但是它们不能同时存在
因为当实例化对象时没有传参,系统
不知道是调用全缺省函数还是无参的函数


6. 析构函数

现在我们知道一个对象是怎么被初始化的
那么一个对象又是怎么被销毁的呢?

析构函数的概念:

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

析构函数的特性:

  • 析构函数名是在类名前加上字符 ~

  • 析构函数无参数无返回值类型

  • 一个类只有一个析构函数,若未显式定义
    系统会自动生成默认的析构函数

  • 析构函数不能重载!

  • 对象生命周期结束时
    C++编译系统系统自动调用析构函数

注:析构函数和构造函数一样
是特殊的函数,不能将它与普通函数相比


7. 对析构函数的理解

有了前面构造函数的铺垫
析构函数就容易理解了,和我们想的一样
编译器自动生成的默认析构函数
只处理自定义类型,而内置类型不会管

那你可能会问:

既然默认析构函数不会处理内置类型
那么内置类型是不是不会销毁?

答案是: 不!

内置类型会在对象生命周期结束时
将它在栈区的空间还给操作系统
所以析构函数不处理在栈区的变量
也没有问题

但是有些变量的指针指向堆区
有由动态开辟出来的空间
这份空间不会主动还给操作系统
需要我们手动写析构函数来释放!

请看以下代码:

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;
	 }
 
	 ~Stack()//析构函数
	 {
		 if (_array)
		 {
			 free(_array);
			 _array = NULL;
			 _capacity = 0;
			 _size = 0;
		 }
 }
private:
	 DataType* _array;
	 int _capacity;
	 int _size;
};
void TestStack()
{
 Stack s;
}

这段代码中,存在在堆区申请的空间
所以不能使用编译器默认生成的析构
而是要用自己写的析构函数去free掉
这块堆区的空间


8. 对默认析构函数的理解

和构造函数一样,默认析构函数
会去调用自定义类型的析构函数

在这里插入图片描述

可以用下面这段代码来验证一下:

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

当d的生命周期结束时
系统会自动调用析构函数
而Date类没有显示写析构函数
就会使用编译器自动生成的析构

此析构函数会去调用Time的析构函数
所以屏幕上就会打印:~Time()

在这里插入图片描述


9. 总结以及拓展

构造函数是析构函数是对立的
一个用于初始化,一个用于销毁对象调用
掌握它们对后面类和对象的学习很重要

拓展1:

类的六个默认函数:

在这里插入图片描述

现在已经学了构造和析构函数!


拓展2:

C++11新增内容:

C++11新增了一个功能:

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

例如:

class Time
{
public:
	 Time()
	 {
	 cout << "Time()" << endl;
	 _hour = 0;
	 _minute = 0;
	 _second = 0;
 }
private:
	 int _hour = 1;//声明的时候给缺省值
	 int _minute = 1;
	 int _second = 1;
};

如果用户没有显示传参
那么hour,minute,second
的值都会初始化为1


🔎 下期预告:拷贝构造函数 🔍

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

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

相关文章

Opencv 细节补充

1.分辨率的解释 •像素&#xff1a;像素是分辨率的单位。像素是构成位图图像最基本的单元&#xff0c;每个像素都有自己的颜色。 •分辨率&#xff08;解析度&#xff09;&#xff1a; a) 图像分辨率就是单位英寸内的像素点数。单位为PPI(Pixels Per Inch) b) PPI表示的是每英…

从零开始 Spring Cloud 7:Gateway

从零开始 Spring Cloud 7&#xff1a;Gateway 图源&#xff1a;laiketui.com Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关&#xff0c;它旨…

系统集成|第三章(笔记)

目录 第三章 系统集成专业技术3.1 信息系统建设3.1.1 信息系统3.1.2 信息系统集成 3.2 信息系统设计3.3 软件工程3.4 面向对象系统分析与设计3.5 软件架构3.5.1 软件的架构模式3.5.2 软件中间件 3.6 典型应用集成技术3.6.1 数据库与数据仓库技术3.6.2 Web Services 技术3.6.3 J…

区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型

区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型 目录 区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRF随机森林分位数回归时间序列区间预测模型&#xff1…

SpringCloud学习路线(10)——分布式搜索ElasticSeach基础

一、初识ES &#xff08;一&#xff09;概念&#xff1a; ES是一款开源搜索引擎&#xff0c;结合数据可视化【Kibana】、数据抓取【Logstash、Beats】共同集成为ELK&#xff08;Elastic Stack&#xff09;&#xff0c;ELK被广泛应用于日志数据分析和实时监控等领域&#xff0…

java——继承

&#x1f384;&#x1f384;&#x1f384;继承 &#x1f346;&#x1f346;继承的概念&#xff1a; 继承(inheritance)机制&#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类&#xff08;父类&#xff09;特性的基础上进行扩展…

挑战css基础面试题

挑战css基础面试题一&#xff0c;看看你能做出来吗 文章目录 前言一、盒模型二、如何实现一个最大的正方形三、文本一行水平居中&#xff0c;多行居左四、画一个三角形五、BFC理解六、两栏布局&#xff0c;左边固定&#xff0c;右边自适应&#xff0c;左右不重叠最后 前言 本片…

springboot快速整合腾讯云COS对象存储

1、导入相关依赖 <!--腾讯云COS--><dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId><version>3.0.1</version></dependency><dependency><groupId>com…

【C语言】指针---初阶

&#x1f341; 博客主页:江池俊的博客 &#x1f341;收录专栏&#xff1a;C语言——探索高效编程的基石 &#x1f341; 如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏&#x1f31f; 三连支持一下博主&#x1f49e; 目录 一、指针是什么&#xff1f; 1.1指…

FTP服务器无法连接解决办法

FTP服务器无法连接解决办法 目录 一&#xff0e; 报错状态二&#xff0e; 解决办法三&#xff0e; 总结 一&#xff0e; 报错状态 二&#xff0e; 解决办法 &#xff08;确保客户机与服务器可以ping通的情况下&#xff0c;再进行下面操作&#xff09; 检查ftp地址是否输错。默…

Kendo UI,一个加速Web应用界面开发的JavaScript组件库!

Kendo UI是什么&#xff1f; 首先&#xff0c;Kendo UI是一个由四个JavaScript UI库组成的包&#xff0c;这些库是专为jQuery、Angular、React和Vue原生构建的&#xff0c;每一个都是用一致的API和主题构建的。所以无论开发者怎么选择&#xff0c;所开发的Web应用始终保持了现…

QueryWrapper,LambdaQueryWrapper用法简介(MyBatis Plus进阶)

目录 一、项目结构及数据库内容如图二、数据库内容三、代码示例 关于如何使用MyBatis Plus自动生成service&#xff0c;mapper&#xff0c;domain参考我的这篇博客&#x1f449;使用MyBatis Plus自动生成service&#xff0c;mapper&#xff0c;domain 一、项目结构及数据库内容…

使用Docker构建LNMP环境并运行Wordpress网站平台

使用Docker构建LNMP环境并运行Wordpress网站平台 1.基于Dockerfile构建LNMP镜像1.1 基于Dockerfile构建nginx镜像1.1.1 修改/usr/local/nginx/conf/nginx.conf文件1.1.2 再次修改nginx服务的Dockerfile文件&#xff08;多级构建&#xff09;1.1.3 创建安装环境依赖包的镜像 1.2…

系统设计《System Design Interview》读书笔记

设计性能认知 延时 操作名称时间1级缓存引用0.5ns2级缓存引用7ns互斥锁/解锁100ns主存引用100ns用zippy压缩1k字节10,000ns10μs通过1GB网络传输2KB字节20,000ns 20μs内存按照顺序读取1MB250,000ns250μs同一个数据中心内的往返500,000ns 500μs磁盘寻找10,000.000ns10ms从…

Qt - .ui 文件的使用

文章目录 目录工具栏Dock Widget代码控制 ui添加资源添加文件 目录 子目录只能输入英文&#xff0c;想要显示中文&#xff0c;可以修改右下方表中的 text 属性&#xff1a; 工具栏 让工具栏共用 菜单栏的 new 和 open&#xff0c;只需将下方列表的控件&#xff0c;拖拽到工具栏…

解决@Scope(“prototype“)不生效的问题

目录 Scope(“prototype“)不生效Scope(“prototype“)正确用法——解决Bean多例问题 1.问题&#xff0c;Spring管理的某个Bean需要使用多例2.问题升级3. Spring给出的解决问题的办法&#xff08;解决Bean链中某个Bean需要多例的问题&#xff09; Scope(“prototype“)不生效 …

STM32(HAL库)驱动st7789LCD屏幕(7引脚240*240)

目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 屏幕引脚配置 2.3 项目生成 3、KEIL端程序整合 3.1 LCD驱动添加 3.2 函数修改 3.2.1 lcd.h修改 3.2.2 lcd_innit.h 修改 3.2.3 lcd.c修改 3.2.4 lcd_inut.c修改 3.3 主函数代码 3.3…

VsCode上传到gitee码云仓库详细教程

首先下载git&#xff0c;地址:https://git-scm.com/downloads 1、到你要提交项目的gitee的项目中&#xff0c;右键点击Git Bash Here进入&#xff0c;进入后按顺序输入&#xff1a; 2、第二步输入你的gitee码云账户 输入ssh-keygen -t ed25519 -C "xxxxxxxxxxxxxxxxx&qu…

docker部署应用的三种方式——最后一种直接使用shell脚本一键化部署

docker命令部署 拉取ubuntu的基础镜像 docker pull ubuntu注意基础镜像是压缩版的&#xff0c;只保证能够运行项目的最基础条件&#xff0c;很多命令都是没有的&#xff0c;在使用过程中如果需要那些命令需要提前安装。 安装openjdk sudo apt install openjdk-11-jdk安装mys…