20

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

例如

class A
{
      private: 
      int a;
      int b;

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

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

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

在这种情况下,我们需要将 A 的析构函数标记为 virtual 吗?

4

6 回答 6

31

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

A * a = new B;
delete a;

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

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

如果操作数的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。

于 2010-01-14T17:06:12.650 回答
20

The purpose of virtual destructor (i.e. the purpose of making a destructor virtual) is to facilitate the polymorphic deletion of objects through delete-expression. If your design does not call for polymorphic deletion of objects, you don't need virtual destructors. Referring to your example, if you'll ever have to delete an object of type B through a pointer of type A * (polymorphic deletion), you'll need virtual destructor as high up in the hierarchy as A. That's how it looks from a formal point of view.

(Note, BTW, as Neil said, that what's important is how you create/delete your class objects, not how classes manage their internal memory.)

As for the good programming practices... It depends on your intent and your design in the end. If your classes are not designed to be polymorphic at all (no virtual methods whatsoever), then you don't need virtual destructors. If your class is polymorphic (have at least one virtual method), then making the destructor virtual "just in case" might be a very good idea, and in this case it bears virtually zero performance/memory penalty with it.

The latter is usually expressed as a rather well-known good practice guideline: if your class has at least one virtual method, make the destructor virtual as well. Although from the formal point of view a virtual destructor might not be really needed there, it is still a pretty good guideline to follow.

Classes that have no resources but can form polymorphic hierarchies should always define empty virtual destructors, except that it is perfectly sufficient to define an explicit empty (and even pure) virtual destructor at the very base of the hierarchy. All other destructors will become virtual automatically, even if they are defined implictly by the compiler. I.e. you don't have to explicitly define an empty destructor in every class. Just the base is enough.

于 2010-01-14T17:10:40.690 回答
4

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

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

于 2010-01-14T17:05:39.607 回答
0

父类的析构函数总是被自动调用,如果没有显式声明 dtor,则总是生成默认的 dtor。在您的示例中,A 和 B 都不需要具有重要的 dtor。

如果你的类有虚函数,那么额外的虚 dtor 不会有什么坏处,而且是很好的做法。如果您的类分配内存或任何其他资源(例如打开文件),则需要 dtor 在销毁时再次释放该资源。

于 2010-01-14T17:07:42.943 回答
0

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

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

于 2010-01-14T17:43:05.227 回答
-1

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

于 2012-09-06T04:23:01.017 回答