析构函数

299 阅读3分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战

💦 概念

前面通过构造函数的学习,我们知道一个对象时怎么来的,那一个对象又是怎么没呢的 ???

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

class Date
{
public:
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;	
	}
	~Date()
	{
		cout << "~Date()" << endl;//证明我来过
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	return 0;
}

📝 说明 

像 Date 这样的类是不需要析构函数的,因为它内部没有什么资源需要清理 

💦 特性

析构函数是特殊的成员函数。

其特征如下:

1️⃣ 析构函数名是在类名前加上字符 ~。

2️⃣ 无参数无返回值 (不支持重载)。

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

4️⃣ 对象生命周期结束时,C++ 编译系统系统自动调用析构函数。


❓ 析构函数有什么意义 ❔

析构函数具体有什么意义要看具体是什么类,哪些类的析构函数是有意义的呢 ❓

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		if(_a == nullptr)
		{
			cout << "malloc fail" << endl;
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		free(_a);
		_a = nullptr;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
int main()
{
	Stack st;
	return 0;
}

📝 说明

在之前我们写栈时都需要写一个 Destroy 在程序结束前销毁动态开辟的内存,很多童鞋可能在使用完动态开辟的内存没有 Destroy 导致后面的一些内存泄漏的操作。而析构函数的出现就是为了解决这种场景的,对象实例化后,同构造函数一样,它不需要我们主动调用,它是在对象生命周期结束后自动调用,注意析构函数没有参数所以不能重载。

构造函数是为了替代 Init,析构函数是为了替代 Destroy。 在这里插入图片描述

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

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		if(_a == nullptr)
		{
			cout << "malloc fail" << endl;
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
int main()
{
	Stack st;
	return 0;
}

📝 说明

与构造函数类似,我们不写,编译器默认生成的构造函数也会做偏心的处理

1、内置类型成员不处理 2、自定义类型成员会去调用它的析构函数

为什么内置类型不处理 ❓

因为它不好处理,如果这个指针是一个文件指针,那你也要去 free 吗 ???

那对于什么样的类可以不写析构呢或者它的价值是什么 ❓

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		if(_a == nullptr)
		{
			cout << "malloc fail" << endl;
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		free(_a);
		_a = nullptr;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
private:
	 Stack _pushST;
	 Stack _popST;	
};
int main()
{
	MyQueue mq;
	return 0;
}

📝 说明

这是之前的一个题 —— 两个栈实现队列

现在对于 MyQueue,我们可以不写构造函数和析构函数,让编译器自动生成构造函数和析构函数也可以 Init 和 Destroy,具体如下:

1、初始化 _pushST 和 _popST 在这里插入图片描述 2、销毁 _pushST 和 _popST 在这里插入图片描述 💨 由以上就可以看出编译器默认生成的析构函数也是有价值的