在本教程中,我们将学习 C++ 析构函数、虚析构函数以及纯虚析构函数。通过本教程,您还将清楚地了解析构函数何时被调用,以及它们的规则和规定。
删除对象的成员函数称为析构函数。当对象离开其作用域时,编译器会自动调用析构函数。析构函数是特殊的成员函数,其行为与构造函数完全相反;构造函数初始化对象,而析构函数销毁(或删除)对象。
析构函数是构造函数的逆操作,其定义方式与构造函数类似。析构函数主要用于销毁类对象。在一个类中,它只能定义一次,并且必须与类同名。它与构造函数一样会自动调用。但在它前面会添加一个波浪号(~)。
当类的对象被销毁时,析构函数通常用于释放内存并为对象和类成员执行其他清理工作。当类对象超出其作用域或被有意消除时,就会调用析构函数。
~className{
// Some code
};
示例 1
class X {
public:
// Constructor for class X
X();
// Destructor for class X
~X();
};
示例 2
#include<iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<"\n Constructor executed";
}
~Test()
{
cout<<"\n Destructor executed";
}
};
main()
{
Test t;
return 0;
}
输出
Constructor executed Destructor executed
当对象离开其作用域时,析构函数会自动调用。
C++ 中的析构函数主要在以下情况中被调用:
由于它们不接受任何参数也不返回任何值,析构函数与普通成员函数不同。析构函数名称以波浪号 (~) 开头,并且与它们的类同名。
当一个项从作用域中删除或被删除时,会发生以下一系列事件来完成其销毁:
当使用基类类型的指针删除具有非虚析构函数的派生类对象时,会导致未定义的行为。通过在基类定义中添加虚析构函数可以解决此问题。
基类的析构函数可以是虚函数。每当执行向上转型时,基类的析构函数必须设置为虚函数,以确保程序终止时对象被正确销毁。
静态转换操作用于打印 void 指针的内容。它将指针的 void* 类型更改为指针所存储地址的适当数据类型。
#include <iostream>
using namespace std;
// declare a class
class base {
public:
// Destructor
~base() {
cout << "The Destructor base." << endl;
}
};
class derived : publicbase {
public:
// Destructor
~derived() {
cout << "The Destructor derived." << endl;
}
}
int main() {
base* b = new derived; // Upcasting
delete b;
return 0;
}
输出
The Destructor base
解释
上述示例中的 `delete b` 命令只会调用基类的析构函数,这是不希望的,因为它阻止了派生类对象的销毁,因为它的析构函数从未被调用。这会导致内存泄漏。
#include <iostream>
using namespace std;
// declare a class
class base {
public:
virtual ~base() {
cout << "The Destructor base." << endl;
}
};
class derived : publicbase {
public:
~derived() {
cout << "The Destructor derived." << endl;
}
}
int main() {
base* b = new derived; // Upcasting
delete b;
return 0;
}
输出
The Destructor base The Destructor derived
解释:当基类中存在虚析构函数时,期望的行为是首先调用派生类的析构函数,然后调用基类的析构函数。
当析构函数的初始值设为 0 时,它被称为虚析构函数,并在基类中声明。纯虚析构函数是另一个选项,类似于虚析构函数。但是,它必须在基类中声明。
虚析构函数和纯虚析构函数的主要区别在于,纯虚析构函数会使其基类成为抽象类,这意味着您将无法创建该类的对象。
派生类不一定需要包含纯虚析构函数。