【Qt】【C++】虚析构函数及 virtual ~Base() = default
1. 虚析构函数的作用
虚析构函数的主要作用是避免内存泄漏。当基类指针指向子类对象时,如果基类的析构函数不是虚函数,那么在删除基类指针时,只会调用基类的析构函数,而不会调用子类的析构函数。这会导致子类的资源没有被正确释放,从而造成内存泄漏。
2. 代码
- Test.cpp
#ifndef TEST_H
#define TEST_H#include <qdebug.h>//虚析构函数
class Base1
{
public:virtual ~Base1() { qDebug() << "Base1 del"; }virtual void show() { qDebug() << "Base1 show"; }
};class Derived1 : public Base1
{
public:~Derived1() { qDebug() << "Derived1 del"; }virtual void show() override { qDebug() << "Derived1 show"; }
};//普通析构函数
class Base2
{
public:~Base2() { qDebug() << "Base2 del"; }virtual void show() { qDebug() << "Base2 show"; }
};class Derived2 : public Base2
{
public:~Derived2() { qDebug() << "Derived2 del"; }virtual void show() override { qDebug() << "Derived2 show"; }
};#endif // TEST_H
- main.cpp
#include "Test.h"int main(int argc, char *argv[])
{Base1* test1 = new Derived1;test1->show();delete test1;qDebug() << "";Base2* test2 = new Derived2;test2->show();delete test2;return 0;
}
- 结果
Derived1 show
Derived1 del
Base1 delDerived2 show
Base2 del
- 结论
- 虚析构函数的例子中,调用了子类的析构函数
- 正常析构函数的例子中,没有调用子类的析构函数
3. virtual ~Base() = default的作用
在 C++11 中,virtual ~base() = default
是一种显式声明默认析构函数的方式。它的主要作用是让编译器生成默认的析构函数,同时保留其虚函数的特性
。这种用法在现代 C++ 编程中非常重要,尤其是在涉及继承和多态的场景中。
-
保留虚函数特性:当基类的析构函数被声明为虚函数时,派生类的析构函数会被正确调用。这对于通过基类指针删除派生类对象至关重要。如果基类的析构函数不是虚函数,可能会导致资源泄漏。
-
显式默认行为:使用
= default
明确表示析构函数的行为是由编译器生成的,而不是用户自定义的。这种方式可以提高代码的可读性和维护性。 -
支持隐式移动操作:如果析构函数被用户定义(即使是空实现),编译器将不会生成隐式的移动构造函数和移动赋值运算符。而使用
= default
可以避免这一问题,保留隐式的移动操作。
4. virtual ~Base() = default 与 virtual ~base() {} 的区别
-
性能优化:
= default
让编译器生成的析构函数更高效,因为它直接调用编译器内部的实现,而不是用户定义的空函数。 -
隐式移动支持:如果使用
virtual ~base() {}
,编译器会认为析构函数是用户定义的,从而禁用隐式的移动构造函数和移动赋值运算符。而 = default 不会影响这些操作。 -
代码意图清晰:
= default
明确表达了程序员希望使用编译器生成的默认行为,而不是自定义逻辑。
5. 代码模板
#ifndef TEST_H
#define TEST_H//虚析构函数
class Base
{
public:virtual ~Base() = default;virtual void show();
};#endif // TEST_H