C++教程-C++中的虚析构函数

C++中的虚析构函数
在C++中,析构函数是一个类的成员函数,用于释放由该类对象占用的空间或删除超出作用域的对象。析构函数的名称与类中构造函数的名称相同,但析构函数在其函数名称之前使用波浪符(~)。
虚析构函数
虚析构函数用于在使用基类指针对象删除派生类实例时释放派生类对象或实例分配的内存空间。基类或父类的析构函数使用虚拟关键字,确保在运行时同时调用基类和派生类的析构函数,但先调用派生类的析构函数,然后调用基类的析构函数以释放两个析构函数占用的空间。
为什么要在C++中使用虚析构函数?
当类中的对象超出作用域或执行main()函数即将结束时,析构函数会自动被调用,以释放类的析构函数占用的空间。当删除指向派生类的基类指针对象时,由于编译器的早期绑定,只会调用父类的析构函数。这种情况下,会跳过调用派生类的析构函数,导致程序中的内存泄漏问题。如果我们在基类中的析构函数前面使用带有虚拟关键字的析构函数波浪符(~),则可以确保先调用派生类的析构函数,然后再调用基类的析构函数以释放继承类中两个析构函数占用的空间。
编写一个在C++中不使用虚析构函数展示析构函数的未定义行为的程序。
#include<iostream>
using namespace std;
class Base
{
public:
Base() // 构造函数
{
cout << "\n Base类的构造函数";
}
~Base() // 析构函数
{
cout << "\n Base类的析构函数";
}
};
class Derived: public Base
{
public:
Derived() // 构造函数
{
cout << "\n Derived类的构造函数" ;
}
~Derived() // 析构函数
{
cout << "\n Derived类的析构函数" ; /* 不调用析构函数来释放其空间。 */
}
};
int main()
{
Base *bptr = new Derived; // 创建一个基类指针对象
delete bptr; /* 在这里调用指针对象来删除析构函数占用的空间。*/
}
输出:
从上面的输出可以看出,当编译器编译代码时,它调用main函数中的指针对象,该指针对象引用了基类。因此,它执行基类的构造函数(),然后转到派生类的构造函数()。之后,它删除由基类析构函数和派生类析构函数占用的指针对象。基类指针仅删除基类的析构函数,而不调用派生类的析构函数。因此,程序中会发生内存泄漏。
注意:如果基类析构函数不使用虚关键字,只会调用基类析构函数或删除其占用的空间,因为指针对象指向基类。因此,不会调用派生类的析构函数来释放派生类使用的内存,这导致派生类的内存泄漏。
编写一个在C++中使用虚析构函数展示析构函数行为的程序。
#include<iostream>
using namespace std;
class Base
{
public:
Base() // 构造函数
{
cout << "\n Base类的构造函数"; // 首先输出
}
virtual ~Base() // 定义虚析构函数以调用派生类的析构函数
{
cout << "\n Base类的析构函数";
}
};
// 继承概念
class Derived: public Base
{
public:
Derived() // 构造函数
{
cout << "\n Derived类的构造函数" ; /* 在打印构造函数Base之后,现在会打印它。 */
}
~Derived() // 析构函数
{
cout << "\n Derived类的析构函数"; /* 虚基类的析构函数在调用基类的析构函数之前调用它。 */
}
};
int main()
{
Base *bptr = new Derived; // 一个指针对象引用基类
delete bptr; // 删除指针对象
}
输出:
在上面的程序中,我们在基类中使用了虚析构函数,它在调用基类的析构函数之前调用派生类的析构函数,并释放程序中的空间或解决内存泄漏问题。