如果一个类(具有虚函数)和它的继承类的所有数据成员都是非指针类型(意味着它不能保存任何动态存储器),是否需要将析构函数声明为虚拟?
实施例
class base {
int x;
public:
virtual void fn(){}
};
class der: public base {
int y;
public:
void fn(){}
};
我们需要一个虚拟析构函数吗?
答案 0 :(得分:3)
不,并不总是必要的。这只是一个经验法则,因此并不总是适用。
真正的规则是:
当要通过基类指针删除派生类的对象时,必须声明析构函数
virtual
。
否则,通过基类指针删除派生类对象会调用未定义的行为。 (最可能的结果是只调用基类的析构函数。)
当然,对于新手而言,这个规则是相当满口的,因此更简单的经验法则,几乎总是正确的。您可能通过多态类层次结构中的基类指针管理动态创建的派生类对象非常,并且非常不可能为非多态性执行此操作类层次结构。
答案 1 :(得分:2)
不,这不是必需的,并且在任何时候都这样做甚至会损害性能。
除非delete
实际存储派生类对象的基类指针,否则不会遇到UB(未定义的行为)。因此,您是否需要虚拟析构函数取决于您的代码实际创建和释放对象的方式,而不仅仅依赖于类。
顺便说一下,与基类相比,派生类是否需要任何额外的破坏并不重要 - 如果delete
应用于存储派生类对象地址的基类指针,则缺少虚拟析构函数是UB反正。
答案 2 :(得分:1)
虚拟析构函数确保在有指向基类的指针时调用继承的类析构函数。
在这种特殊情况下,您不需要它,但是用户可以从der
继承另一个类(让它为foo
),该类使用 - 例如 - 动态内存分配。在这种情况下,除非他有一个foo
类型的指针,否则不会调用析构函数。
所以不,它不是“必要的”,但如果你已经拥有至少一个虚拟功能(因此你已经拥有VTABLE),那么也没有任何伤害。如果您假定这些类将由用户继承并使用指向基类的指针释放,则必须使用它。
答案 3 :(得分:0)
是
无论何时创建具有虚函数的类,您都需要将析构函数声明为虚拟。
考虑这种情况 -
base *b = new der();
delete b;
由于您在基指针上操作,因此它不知道它实际上是子类的对象,因此永远不会调用der的析构函数。这可能会导致内存泄漏等其他问题。