C++_CH18_构造函数与析构函数

news2024/11/18 15:38:19

C++_CH18_构造函数与析构函数

1 类的默认成员函数

在编写类的时候,C++编译器会默认生成6个默认的函数,但是不显示出来:
在这里插入图片描述
需要关注以下两个方面:

第一:我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求。
第二:编译器默认生成的函数不满足我们的需求,我们需要自己实现,
	那么如何自己实现?

2 构造函数

构造函数是一种特殊类型的方法,他在类的实例化时被使用。

2.1 一个例子来说明

创建一个Entity类,并给他写一个method,Print(),这样实例化后,调用Print就可以将x,y的值打印到控制台:

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点

	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	e.Print();
	std::cin.get();
	return 0;
}

在低版本的编译器中,得到的输出是两个随机值,当然现在的编译器得到的结果是

0,0

因为X、Y是public的,因此我们可以打印X,Y试试

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点

	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

还是对于高版本的编译器,输出为

00
0,0

但是对于低版本的编译器,则会报错:未初始化局部变量。

2.2 诞生需求

默认为低版本编译器。我们需要在创建实例时,就把X和Y初始化为0,0而不是一个随机值。要一个新的方法。

2.3 Init()方法

在class中添加Init(),来初始化

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	void Init()
	{
		X = 0.0f;
		Y = 0.0f;
	}
	
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	e.Init();
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

此时,在低版本编译器下输出也为:

00
0,0

成功完成了初始化。

但是:这样我们每创建一个实例,都需要调用一次Init,这样十分的麻烦。

2.5 诞生新需求

新需求:我们创建实例的时候就自动完成了Init()类似的操作,不需要额外的代码

2.6 构造函数的诞生

2.6.1 构造函数的特点
1. 没有返回值,不需要写返回值类型
2. 函数名与类名一致
3. 对象实例化时系统会自动调用对应的构造函数。
4.构造函数可以重载。
5.如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函`数,一旦用户显式定义编译器将不再生成。
6.无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函数。但是这三个函数有且只有一个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义。要注意很多同学会认为默认构造函数是编译器默认生成那个叫默认构造,实际上无参构造函数、全缺省构造函数也是默认构造,总结一下就是不传实参就可以调用的构造就叫默认构造。
7.我们不写,编译器默认生成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于自定义类型成员变量,要求调用这个成员变量的默认构造函数初始化。

e.g.

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	Entity()
	{
		X = 0.0f;
		Y = 0.0f;
	}
	
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

output:

00
0,0

此为一个不带参数的构造函数。

2.6.2 带参数的构造函数

以下为带参数构造函数。注意,有两个构造函数,名字都是Entity,此为函数重载。但是构造函数没有重载。

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	Entity()
	{
	}
	
	Entity(float x,float y)
	{
		X = x;
		Y = y; //用参数给成员变量赋值。
	}
	
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e(10.0f,11.0f);
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

output

1011
10,11

2.6.3不想要默认的构造函数

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	Entity() = delete;
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

因为没有默认的构造函数,此时会报错。

3 析构函数

析构函数是构造函数的对立。它用于销毁实例。

3.1 析构函数的特点

1.析构函数名是在类名前加上字符 ~。
2.无参数无返回值。(这里跟构造类似,也不需要加void)
3.一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4.对象生命周期结束时,系统会自动调用析构函数。
5.跟构造函数类似,我们不写 编译器自动生成的析构函数,对内置类型成员不做处理,自定类型成员会调用他的析构函数。
6.还需要注意的是我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类型成员无论什么情况都会自动调用析构函数。
7.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,如Date;但是有资源申请时,一定要自己写析构,否则会造成资源泄漏,如Stack。
8.一个局部域的多个对象,C++规定后定义的先析构。

3.2 实例

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	Entity()
	{
		X = 0.0f;
		Y = 0.0f;
		std::cout<<"完成对象创建"<<std::endl;
	}
	
	~Entity()
	{
		std::cout<<"销毁对象完成"<<std::endl;
	}
	
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

int main()
{
	Entity e;
	std::cout<<e.X<<e.Y<<std::endl;
	e.Print();
	std::cin.get();
	return 0;
}

output

完成对象创建
00
0,0
销毁对象完成

析构函数是在对象的生命结束时运行,这个例子无法看出析构函数实在main函数结束时运行的,我们稍加修改:

#include <iostream>

class Entity
{
public:
	float X,Y; //二维坐标下的(x,y)点
	
	Entity()
	{
		X = 0.0f;
		Y = 0.0f;
		std::cout<<"完成对象创建"<<std::endl;
	}
	
	~Entity()
	{
		std::cout<<"销毁对象完成"<<std::endl;
	}
	
	void Print()
	{
		std::cout<<X<<','<<Y<<std::endl;
	}
};

void func()
{
	Entity e;
	e.Print();
}

int main()
{
	func();
	std::cout<<"HellO"<<std::endl;
	std::cin.get();
	return 0;
}

只要hello是在“销毁对象完成”之后打印的,就证明析构函数是在函数作用域结束的时候调用的。

output:

完成对象创建
0,0
销毁对象完成
HellO

成功证明。
当然用visual studio调试也可以证明。

总之析构函数就防止内存泄露的。

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

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

相关文章

LabVIEW界面输入值设为默认值

在LabVIEW中&#xff0c;将前面板上所有控件的当前输入值设为默认值&#xff0c;可以通过以下步骤实现&#xff1a; 使用控件属性节点&#xff1a;你可以创建一个属性节点来获取所有控件的引用。 右键点击控件&#xff0c;选择“创建” > “属性节点”。 设置属性节点为“D…

实践出真知!8个案例速通栅格系统

在现代设计中&#xff0c;栅格系统作为一种重要的布局方案&#xff0c;能够有效提升设计的秩序感。对于 UI 设计领域&#xff0c;栅格系统也广泛用于跨屏幕的响应式设计&#xff0c;帮助设计师打造更好的多端体验。本文将简要介绍栅格系统的基本概念和搭建方法&#xff0c;并提…

什么是unix中的fork函数?

一、前言 在本专栏之前的文档中已经介绍过unix进程环境相关的概念了&#xff0c;本文将开始介绍unix中一个进程如何创建出新进程&#xff0c;主要是通过fork函数来实现此功能。本文将包含如下内容&#xff1a; 1.fork函数简介 2.父进程与子进程的特征 3.如何使用fork创建新进程…

依赖不对应导致java文件不能正常显示

项目中若出现非正常显示的java文件&#xff0c;检查下是否依赖版本不对应。&#xff08;前提必须是maven项目&#xff09;

网络原理(4)——网络层(IP)、数据链路层

1. IP 协议 基本概念&#xff1a; 主机&#xff1a;配有 IP 地址&#xff0c;但是不进行路由控制的设备 路由器&#xff1a;即配有 IP 地址&#xff0c;又能进行路由控制 节点&#xff1a;主机和路由器的统称 IP 协议报头格式 1) 4 位版本&#xff1a;实际上只有两个取值&…

通义灵码AI 程序员正式发布:写代码谁还动手啊

虽然见不到面 但你已深潜我心 前几天&#xff0c;在 2024 年的杭州云栖大会上&#xff0c;随着通义大模型能力的全面提升&#xff0c;阿里云通义灵码这位中国的首位 AI 程序员也迎来重大的升级。 一年前这位 AI 程序员还只能完成基础的编程任务&#xff0c;到现在可以做到几…

Leetcode 543. 124. 二叉树的直径 树形dp C++实现

问题&#xff1a;Leetcode 543. 二叉树的直径&#xff08;边权型&#xff09; 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。两节点之间路径的 长度 由它们之…

探索未来:MultiOn,AI的下一个革命

文章目录 探索未来&#xff1a;MultiOn&#xff0c;AI的下一个革命背景&#xff1a;为什么选择MultiOn&#xff1f;MultiOn是什么&#xff1f;如何安装MultiOn&#xff1f;简单的库函数使用方法场景应用常见问题及解决方案总结 探索未来&#xff1a;MultiOn&#xff0c;AI的下一…

图表示学习中的Transformer:Graphormer的突破

人工智能咨询培训老师叶梓 转载标明出处 在自然语言处理和计算机视觉等领域&#xff0c;Transformer架构已经成为主导选择。然而&#xff0c;在图级别的预测任务中&#xff0c;它的表现并不如主流的图神经网络&#xff08;GNN&#xff09;变体。这一现象引发了一个思考&#x…

指针变量的自增、自减运算

指针变量的自增、自减运算相比较于普通变量的自增、自减运算又什么区别呢&#xff1f; 让我们先来复习一下普通变量的自增、自减运算 int main() {int i; //定义一个整型变量printf("请输入一个数字&#xff1a;\n");scanf("%d&qu…

JetBrains系列产品无限重置免费试用方法

JetBrains系列产品无限重置免费试用方法 写在前面安装插件市场安装插件 写在前面 支持的产品&#xff1a; IntelliJ IDEA AppCode CLion DataGrip GoLand PhpStorm PyCharm Rider RubyMine WebStorm为了保证无限重置免费试用方法的稳定性&#xff0c;推荐下载安装2021.2.2及其…

QT Creator cmake 自定义项目结构, 编译输出目录指定

1. 目的 将不同的源文件放到不同的目录下进行管理&#xff0c; 如下&#xff1a; build: 编译输出目录 include: 头文件目录 rsources: 资源文件目录 src: cpp文件目录 2. 创建完cmake工程后修改CMakeLists.txt 配置 注 &#xff1a; 这里头文件目录是include, 所以在includ…

CSS05-复合选择器

一、什么是复合选择器 1-1、后代选择器&#xff08;重要&#xff09; 示例1&#xff1a; 示例2&#xff1a; 示例3&#xff1a; 1-2、子选择器 示例&#xff1a; 1-3、并集选择器&#xff08;重要&#xff09; 示例&#xff1a; 1-4、伪类选择器 1、链接伪类选择器 注意事项&am…

CVPR最牛图像评价算法!

本文所涉及所有资源均在 传知代码平台可获取。 目录 概述 一、论文思路 1.多任务学习框架&#xff1a; 2.视觉-语言对应关系&#xff1a; 3.动态损失权重&#xff1a; 4.模型优化和评估&#xff1a; 二、模型介绍 三、详细实现方法 1.图像编码器和语言编码器&#xff08;Image…

德蒂企鹅PAEDIPROTECT:德国医研力作,专为敏感肌婴幼儿量身打造

新生儿的诞生总是伴随着喜悦&#xff0c;也充满着手忙脚乱&#xff0c;尤其是敏感肌宝宝的皮肤护理。宝宝的皮肤如同初绽的花瓣&#xff0c;皮肤角质层薄而脆弱&#xff0c;容易受到外界刺激物的影响&#xff0c;水分流失快&#xff0c;经常会出现干燥、瘙痒、红斑甚至湿疹等症…

【ARM】AMBA和总线

AMBA AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09; 总线是由ARM公司提出的一种开放性的片上总线标准&#xff0c;它独立于处理器和工艺技术&#xff0c;具有高速度低功耗等特点。 总线&#xff1a;系统芯片中各个模块之间需要有接口来连接。总线作…

爬虫类Chrome去除前端无限debugger反调试(轻松分析算法)

文章目录 引言方法1(简易抓包或者分析js适用)方法2(解决实际问题-最简单的方法)方法3(解决实际问题-麻烦点也是学会fiddler的一个功能)第一步&#xff1a;熟悉界面的大致功能意思第二步&#xff1a;保存出需要替换的代码&#xff0c;记住保存位置&#xff0c;待会儿要用第三步&…

【Python篇】详细学习 pandas 和 xlrd:从零开始

文章目录 详细学习 pandas 和 xlrd&#xff1a;从零开始前言一、环境准备和安装1.1 安装 pandas 和 xlrd1.2 验证安装 二、pandas 和 xlrd 的基础概念2.1 什么是 pandas&#xff1f;2.2 什么是 xlrd&#xff1f; 三、使用 pandas 读取 Excel 文件3.1 读取 Excel 文件的基础方法…

如何在精益六西格玛项目实践中激励小组成员保持积极性?

在精益六西格玛项目实践中&#xff0c;激励小组成员保持积极性是推动项目成功与持续改进的关键因素。精益六西格玛作为一种集精益生产与六西格玛管理精髓于一体的管理模式&#xff0c;旨在通过流程优化、质量提升及成本降低&#xff0c;实现企业的卓越绩效。然而&#xff0c;这…

《DevOps实践指南》笔记-Part 3

一篇文章显得略长&#xff0c;本文对应第5-6章、附录、认证考试、参考资源等。 前言、第1-2章请参考Part 1&#xff0c;第3-4章内容&#xff0c;请参考Part 2。 持续学习与实验的技术实践 通过以下方式制定有关提高安全性、持续改进和边做边学的制度&#xff1a; 建立公正的…