虚析构函数:不动态分配内存时是否需要?

时间:2010-01-14 17:02:56

标签: c++ virtual-destructor

如果我的类没有动态分配任何内存,我们是否需要虚拟析构函数?

e.g。

class A
{
      private: 
      int a;
      int b;

      public:
      A();
      ~A();
};

class B: public A
{     
      private:
      int c;
      int d;

      public:
      B();
      ~B();
};

在这种情况下,我们是否需要将A的析构函数标记为虚拟?

6 个答案:

答案 0 :(得分:32)

问题不在于您的类是否动态分配内存。如果类的用户通过A指针分配B对象,然后删除它:

A * a = new B;
delete a;

在这种情况下,如果A没有虚拟析构函数,则C ++ Standard会说您的程序显示未定义的行为。这不是一件好事。

此行为在标准的第5.3.5 / 3节(此处提到delete)中指定:

  

如果操作数的静态类型是   不同于它的动态类型   static类型应该是基类   操作数的动态类型和   静态类型应具有虚拟   析构函数或行为是   未定义。

答案 1 :(得分:19)

虚拟析构函数的目的(即制作析构函数 virtual 的目的)是通过 delete-expression 。如果您的设计不需要对对象进行多态删除,则不需要虚拟析构函数。参考您的示例,如果您必须通过类型为B的指针(多态删除)删除类型为A *的对象,则您需要将虚拟析构函数作为层次结构中的高位A。从正式的角度来看,这就是它的样子。

(注意,BTW,正如Neil所说,重要的是如何创建/删除类对象,而不是类如何管理其内部存储器。)

至于良好的编程习惯......最终取决于你的意图和你的设计。如果您的类根本不是多态的(没有任何虚拟方法),那么您不需要虚拟析构函数。如果你的类是多态的(至少有一个虚方法),那么使析构函数虚拟“以防万一”可能是一个非常好的主意,在这种情况下,它几乎没有性能/内存损失。

后者通常表示为一个众所周知的良好实践指南:如果您的类至少有一个虚拟方法,那么也可以将析构函数设置为虚拟。虽然从形式上看,虚拟析构函数可能并不是真正需要的,但它仍然是一个很好的指导方针。

没有资源但可以形成多态层次结构的类应始终定义空的虚拟析构函数,除了在层次结构的最底层定义显式空(甚至纯)虚拟析构函数是完全足够的。所有其他析构函数将自动变为虚拟,即使它们是由编译器隐含定义的。即您不必在每个类中显式定义空的析构函数。只是基数就足够了。

答案 2 :(得分:4)

释放内存不是析构函数可以执行的唯一关键功能。例如,它也可以用于重置全局状态。不这样做不会泄漏内存,但可能会导致程序中出现其他问题。

此外,即使您的析构函数今天没有做任何有用的事情,也可能在将来某个时候。如果你有继承,没有真正的理由避免使用虚拟析构函数,那为什么不在晚上添加它并在晚上睡得更好呢?

答案 3 :(得分:0)

总是自动调用父类的析构函数,如果没有声明显式的dtor,则始终生成默认的dtor。在你的例子中,A和B都不需要有一个非平凡的dtor。

如果你的班级有虚拟功能,额外的虚拟dtor不会受到伤害,这是一种很好的做法。如果您的类分配内存或任何其他资源(如打开文件),则需要dtor在销毁时再次释放该资源。

答案 4 :(得分:0)

将析构函数声明为虚拟的目的是,只要在指向类型为Derived的对象的Base类型的指针上调用delete,就能够调用派生类的析构函数。不这样做会导致未定义的行为。

如果不动态分配内存,则假设您不需要将析构函数标记为虚拟,这意味着如果不动态分配内存,则不需要调用派生类析构函数,这是错误的。因为您可能仍然在派生类的析构函数中执行其他几个操作,而不仅仅是释放动态分配的内存。例如关闭打开的文件,记录一些信息等。

答案 5 :(得分:-1)

如果你唯一关心的是内存,也许你应该从保护基类析构函数(和/或其他人)开始。然后,如果某些东西没有编译,你会明白为什么。参考:提升::任何方式。