C++类和对象-3

news2024/11/18 15:44:20

承接上一篇博客中内容,讲述完类和对象中构造函数内容之后,这篇博客我们来讲述类和对象中,析构函数的内容。

目录

1.析构函数

2.拷贝构造函数

3.浅拷贝与深拷贝

1.析构函数

在类和对象的构建当中,类中的对象会通过构造函数来完成初始化,与之相应的存在析构函数来对类中的对象进行销毁(释放),它的特点是:

  1. 只能被声明为公有(public);
  2. 析构函数同类名,不过前加会加上~;
  3. 析构函数无任何参数,不能被重载;
  4. 一个类中只能存在一个析构函数;
  5. 无相应的返回类型;
  6. 析构函数在释放一个对象中会被自动调用;

同样的,当一个类中不存在析构函数,系统会默认生成一个析构函数来完成对类中对象的释放。

#include<iostream>

class Point {
private:
	int x;
	int y;
public:
	Point() {

	};
	Point(int xvalue, int yvalue) :x(xvalue), y(yvalue) {

	}
	void Print() {
		std::cout << "(" << x << "," << y << ")" << std::endl;
	}
	~Point() {
		std::cout << "析构函数被调用\n";
	}
};


int main() {
	Point a(1, 1);
	a.Print();
	return 0;
}

当我们执行上述代码,得到结果如下:

我们可以很明显的看出,当我们主函数退出之前,会释放程序创建资源。那么对于类而言,便会调用它的析构函数来释放它所创建的对象,于是我们便在结果上观察到“析构函数被调用”的打印内容。

2.拷贝构造函数

拷贝构造函数也是为我们提供的一种初始化类中对象的方式,它可以用一个已经存在的对象去初始化另外一个对象,并且拷贝构造函数必须为构造函数的一个重载类型,其-【-特点如下:(正如它的名字,通过拷贝来构造对象。)

  1. 拷贝构造函数名字与类相同,不能指定返回类型;
  2. 拷贝构造函数只能由一个参数,并且该参数是该类中其他某一对象引用;
  3. 拷贝构造函数不能被显示调用。

我们照例在Point类中进行书写:

编译并执行得到结果如下:

可以很明显看出,当创建对象a时,会调用构造函数;当通过a来初始化b时,会调用拷贝构造函数。最后在函数退出时,会释放资源,调用两次析构函数,对a和b全部进行释放。

最后,当出现以下三种情况时,拷贝构造函数会被自动调用来初始化对象:

  1. 当用类中一个已经存在的对象去初始化另外一个对象时;
  2. 当函数的形参时类的对象,进行形参和实参结合时;
  3. 当函数的返回值是类的对象,函数执行完成返回调用者时。

对于上述第3条,我们进行一个格外补充说明,当我们设计程序如下这种形式:

对于不同的编译器会存在不同的打印结果,使用vs一些较老版本会将”拷贝构造函数被调用“打印三次。这是因为函数返回值是对象,需要返回给调用者时,程序会默认生成一个临时对象来调用拷贝构造函数,并完成对象的初始化。

对于gcc编译器而言,它会将函数返回对象进行优化,即函数return时并不会创建额外的临时对象和调用拷贝构造函数,所以我们只能在结果中看到”拷贝构造函数被调用“只打印了两次。分别是函数调用之前,和函数执行语句中的两次。

3.浅拷贝与深拷贝

对于类的构造函数,析构函数和拷贝构造函数,当我们不去主动设计它们,系统也会默认为我们生成一份。对于前两者的函数参数列表和函数体都是空的,并不存在内容;不过对于系统默认生成的拷贝构造函数,其中参数列表会具备const引用的类,函数体中会存在对参数类的对象初始化。

对于系统默认生成的拷贝构造函数,在对数据成员进行逐一初始化时,通常并不会存在问题。但是出现一些系统难以完成拷贝赋值的数据类型(如指针……)时,系统默认生成的拷贝构造函数执行时就会发生错误。

于是我们首先对拷贝进行分为,将系统默认生成的拷贝构造函数对成员数据进行逐一初始化的过程,称为“浅拷贝”;对于需要进行我们自己设计拷贝构造函数,来对额外数据成员进行拷贝初始化时,称为“深拷贝”。

我们编写代码如下:

#include<iostream>

typedef int DataType;

class Stack {
private:
	DataType*_array;
	size_t _size;
	size_t _capacity;
public:
	Stack(size_t capacity = 10) {
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (_array == nullptr) {
			std::cout << "malloc failed\n";
			return;
		}

		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data) {
		_array[_size] = data;
		_size++;
	}
	~Stack() {
		if (_array) {
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
};

int main() {
	Stack s1;
	s1.Push(1);
	s1.Push(2);

	Stack s2(s1);
	return 0;
}

通过执行上述代码,编译器便会报错,因为我们通过对象s2来对对象s1进行拷贝,s2和s1中的内容便会完全一致。于是当函数运行结束退出时,会调用两次析构函数来分别对s1和s2进行释放,可是s1和s2所指向的内存空间是同一块,所以会导致同一块内存空间被销毁两次,程序崩溃。

总结:当我们类中对象涉及到资源的申请时,使用系统默认的拷贝构造函数函数进行拷贝过后,在析构函数进行资源释放时会造成同一块内存销毁多次,导致程序崩溃。浅拷贝是行不通的,那么一旦类中涉及到资源申请,我们一定要设计自己的拷贝构造函数,进行深拷贝。

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

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

相关文章

Jenkins配置邮箱发送报告

本文以qq邮箱为例 1.下载Email Extension Plugin插件 2.在Manage Jenkins--System&#xff0c;Jenkins Location下配置理员邮件 Extended E-mail Notification 下配置Jenkins SMTP server&#xff08;邮箱服务&#xff09;、SMTP Port&#xff08;邮箱端口&#xff09;、Cred…

c++学习(day4)

文章目录 一. 友元&#xff08;friend&#xff09;1 友元函数1.1 全局函数作为友元函数1.2 类的成员函数作为友元函数&#xff08;了解&#xff09; 2. 友元类3. 使用友元的注意事项 二. 常成员函数和常对象&#xff08;const&#xff09;1. 常成员函数2. 常对象3. mutable关键…

【微服务笔记17】微服务组件之Gateway实现动态路由、配置路由规则、路由过滤器

这篇文章&#xff0c;主要介绍微服务组件之Gateway实现动态路由、配置路由映射规则、路由过滤器。 目录 一、动态路由配置 1.1、动态URI路由配置 &#xff08;1&#xff09;引入eureka客户端依赖 &#xff08;2&#xff09;添加路由配置 1.2、服务名称转发配置 二、断言配…

基于 Windows 安装 ESP32 Arduino 软件开发环境

ESP32 Arduino 源码库&#xff1a;arduino-esp32ESP32 Arduino 环境搭建说明&#xff1a;About Arduino ESP32 其他软件环境需求&#xff1a; Git 环境 1、安装 Arduino 软件 可在 Arduino 官网 获取 Windows 端 Arduino 安装包&#xff0c;如下&#xff1a; 使用如下 .exe 一…

JVM类加载过程

文章目录 1、加载2、链接2.1 验证2.2 准备2.3 解析 3、初始化3.1 类初始化练习3.2 懒汉式单例练习 4、类加载器4.1 启动类加载器4.2 扩展类加载器4.3 双亲委派模式4.4 线程上下文类加载器4.4 自定义类加载器 5、运行时优化5.1 即时编译逃逸分析方法内联&#xff08;Inlining&am…

StressAppTest的简介

StressAppTest的全称是Stressful Application Test (stressapptest) 的简称http://code.google.com/p/stressapptest/ 这里我们可以将其简化为SAT。 SAT试图让来自处理器和I/O到内存的数据尽量随机化,以创造出模拟现实的环境来测试现在的硬件设备是否稳定。 SAT的大概作用如…

【Mysql 学习笔记】

Mysql 笔记记录 MySQL学习笔记一、 DDL1. DDL 查询和创建数据库2. DDL 修改、删除、使用数据库3. DDL 查询数据表4. DDL 创建数据表5. DDL 修改数据表6. DDL 删除数据表 二、DML MySQL学习笔记 一、 DDL 1. DDL 查询和创建数据库 #查询所有数据库 SHOW DATABASES; #查询某个数…

PMP项管2023年5月的备考准备攻略!现在看还来得及!

2023年共有4次PMP考试&#xff0c;分别是3月、5月、8月、11月&#xff0c;由于3月份考试不开放新报名&#xff0c;所以第一次备考PMP的同学可以选择参加5月份考试。那么&#xff0c;现在备考5月份PMP考试还来得及吗&#xff1f; 现在开始备考5月PMP考试&#xff0c;时间是非常…

蓝牙技术|消息称三星正研发智能戒指Galaxy Ring

根据韩媒 MT 报道&#xff0c;三星内部正在开发继 Galaxy Watch、Galaxy Fit 之后的另一款健康追踪设备 Galaxy Ring。 报道称这款智能戒指配备 PPG&#xff08;光电容积脉搏波&#xff09;传感器和 ECG&#xff08;心电图&#xff09;传感器&#xff0c;可以准确追踪佩戴者的…

云智慧助力MLOps加速落地

背景 随着数字化和计算能力的发展&#xff0c;机器学习&#xff08;Machine Learning&#xff09;技术在提高企业生产力方面所涌现的潜力越来越被大家所重视&#xff0c;然而很多机器学习的模型及应用在实际的生产环境并未达到预期&#xff0c;大量的ML项目被证明是失败的。从…

云计算中的网络安全技术及其应用

云计算已经成为当今企业信息化的主要选择之一。它提供了可靠的数据存储和处理能力&#xff0c;同时降低了企业的IT成本。然而&#xff0c;云计算的安全问题也随之而来。网络安全技术的应用对于保护云计算的安全至关重要。本文将探讨云计算中的网络安全技术及其应用&#xff0c;…

Golang每日一练(leetDay0041) 股票买卖4题

目录 121. 买卖股票的最佳时机 &#x1f31f; 122. 买卖股票的最佳时机 II &#x1f31f;&#x1f31f; 123. 买卖股票的最佳时机 III &#x1f31f;&#x1f31f;&#x1f31f; 188. 买卖股票的最佳时机 IV &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每…

2023第六届世界燕窝及天然滋补品博览会

2023上海燕窝展|上海燕博会|虫草节、鱼胶、灵芝、海参、滋补品展|滋补大会 摘要&#xff1a;燕博会、上海燕窝展、上海燕博会、2023上海燕博会、2023上海燕窝展、2023中国燕窝展、2023燕窝展&#xff0c;2023原装进口燕窝展&#xff0c;2023干制燕窝展,2023即食燕窝展,2023燕窝…

前端开发中有哪些常用的数组操作方法?

javascript数组 简介 JavaScript 数组用于在单一变量中存储多个值。 JavaScript数组是无类型的&#xff0c;数组元素可以是任意类型&#xff0c;并且同一个数组中元素类型也可以不同。 实例 var cars ["Saab", "Volvo", "BMW"];什么是数组&…

探索【Stable-Diffusion WEBUI】的插件:画布扩绘(Outpaint)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;局部重绘&#xff08;Inpaint&#xff09;&#xff08;二&#xff09;画布扩绘&#xff08;Outpaint&#xff09;&#xff08;2.1&#xff09;图片画布扩大&#xff08;插件&#xff1a;OpenOutpaint&#x…

回炉重造九---DNS服务器

1、DNS服务器的相关概念和技术 1.1 DNS服务器的类型 主DNS服务器从DNS服务器缓存DNS服务器&#xff08;forward DNS服务器{转发器}&#xff09; 1.1.1 主DNS服务器的作用 管理和维护所负责解析的域内解析库的服务器1.1.2 从DNS服务器的作用 从主服务器或从服务器“复制”解…

检测并打印C++编译器支持的feature(附Visual Studio 2022和gcc-12测试、对比结果)

C标准快速迭代&#xff0c;不同的系统平台和编译器对C各种新功能的支持不同&#xff0c;通过这个程序可以测试所用编译器对各个版本C的支持情况。另一方面&#xff0c;可以在代码中通过这些宏针对不同版本编写不同的代码分支。 源码下面附上Visual Studio 2022的测试结果&#…

32道子网划分习题详细解析

目录 1 子网划分概念&#xff1a; 2 划分方法&#xff1a; 子网划分方法&#xff1a;段&#xff0c;块&#xff0c;数的计算三步。 段就是确定ip地址段中既有网络地址&#xff0c;又有主机地址的那一段是四段中的那一段&#xff1f; 块就确定上一步中确定的那一段中的主机…

【C语言】21-结构体

本文目录 • 一、什么是结构体 • 二、结构体的定义 • 三、结构体变量的定义 • 四、结构体的注意点 • 五、结构体的初始化 • 六、结构体的使用 • 七、结构体数组 • 八、结构体作为函数参数 • 九、指向结构体的指针 说明&#xff1a;这个C语言专题&#xff0c;是学习iOS开…

算法设计与智能计算 || 专题七: 主成分分析的统计学视角

主成分分析的统计学视角 文章目录 主成分分析的统计学视角PCA 的统计学视角1. 寻找第一个主成分2. 获取第二个主成分3. 非零均值随机变量的主元4. 零均值随机变量的样本主元5. PCA 降维案例 主成分分析是将高维空间中的数据集拟合成一个低维子空间的方法&#xff0c;到目前为止…