在该多态析构场景下能否避免使用带函数体的纯虚函数?
关于避免带函数体纯虚函数的解决方案及设计确认
嘿,先给你吃个定心丸:你当前的代码其实已经完全避免了带函数体的纯虚函数,而且核心思路是正确的!咱们一步步拆解清楚:
1. 为什么当前方案可行?
你把基类parent的析构函数声明为普通虚函数(而非纯虚),这是C++中处理多态对象销毁的标准正确做法:
- 当你通过
parent*指针delete派生类对象时,虚析构函数会保证先调用派生类的析构函数,再调用基类的析构函数,彻底释放所有资源,避免内存泄漏。 - 基类的虚析构函数有函数体是完全合理的,完全没必要把它改成带函数体的纯虚析构(哪怕C++允许这么做)。
2. 你的设计需要优化的细节
虽然核心逻辑没问题,但有两个细节可以补上,避免潜在bug:
- 初始化指针数组:你的
list类中的parent* ar[arlen]默认是未初始化的,里面可能是野指针。建议在list的构造函数里把所有指针初始化为nullptr——因为delete nullptr是安全的,但delete野指针会直接导致未定义行为。 - 禁用拷贝操作:默认的拷贝构造/赋值运算符会对指针数组做浅拷贝,导致多个
list实例共享同一组对象,销毁时会重复delete同一个对象,触发崩溃。所以需要显式禁用这两个操作。
优化后的代码示例
#include <iostream> #define arlen 10 class parent{ public: // 普通虚析构,无需纯虚 virtual ~parent() {} void somefunction(); }; // 基类成员函数定义可以放在类外(按需) void parent::somefunction() { // 基类默认实现 } class child1: public parent{ public: ~child1() {} void somefunction(); }; void child1::somefunction() { // child1的自定义实现 } class child2: public parent{ public: ~child2() {} void somefunction(); }; void child2::somefunction() { // child2的自定义实现 } class list{ public: parent* ar[arlen]; // 构造函数初始化所有指针为nullptr list() { for (int n = 0; n < arlen; ++n) { ar[n] = nullptr; } } ~list(){ for (int n=0; n<arlen; n++) { delete ar[n]; } } // 禁用拷贝构造和拷贝赋值,避免浅拷贝问题 list(const list&) = delete; list& operator=(const list&) = delete; }; int main(){ // 示例用法 list myList; myList.ar[0] = new child1(); myList.ar[1] = new child2(); // 销毁myList时会自动释放所有派生类对象 return 0; }
3. 什么时候才需要带函数体的纯虚函数?
顺带提一句,带函数体的纯虚函数是非常小众的用法,一般只在这种场景下使用:你想强制派生类必须重写某个成员函数,但基类又需要提供一个默认实现(派生类可以选择调用这个默认实现)。但在析构函数的场景里,虚析构的机制已经完美解决了多态销毁的问题,完全不需要这种操作。
内容的提问来源于stack exchange,提问作者Mathew
相关产品推荐
相关产品推荐

