0%

C++关于虚析构函数

虚析构函数问题

引用标准中原文: 一条有用的方针,是任何基类的析构函数必须为公开且虚, 或受保护且非虚。

虚析构这个概念被设计出来就是为了解决基类指针指向派生类实例的析构问题,当一个基类指针指向派生类实例然后进行delete该指针时,只会执行基类析构函数而派生类的析构函数不会被执行,这将导致派生类构造的资源不会被正确释放,造成内存泄漏。如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

struct Base
{
Base() { std::cout << "Base Construct!" << std::endl; }
/// 该析构函数为错误示例,严禁这样写.
~Base() { std::cout << "Base Deconstruct!" << std::endl; }
};

struct Derived : public Base
{
Derived() { std::cout << "Derived Construct!" << std::endl; }
~Derived() { std::cout << "Derived Deconstruct!" << std::endl; }
};

int main()
{
{
/** 使用基类指针指向派生类实例 */
Base* BasePtr = new Derived;
delete BasePtr;
}
system("pause");
}

运行结果:

Virtual DeConstruct Debug

可以看到派生类没有被析构,如要解决该问题在基类析构函数处加上virtual关键字即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

struct Base
{
Base() { std::cout << "Base Construct!" << std::endl; }
/** 正确写法: 加上关键字virtual, 后面函数体可写可不写,或者直接使用=default都行。 */
virtual ~Base() { std::cout << "Base Deconstruct!" << std::endl; }
};

struct Derived : public Base
{
Derived() { std::cout << "Derived Construct!" << std::endl; }
~Derived() { std::cout << "Derived Deconstruct!" << std::endl; }
/// 或者 virtual ~Derived() override {}
};

int main()
{
{
/** 使用基类指针指向派生类实例 */
Base* BasePtr = new Derived;
delete BasePtr;
}
system("pause");
}

运行结果:

Virtual DeConstruct Debug Correct