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

cpp*_*dev 20 c++ virtual-destructor

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

例如

class A
{
      private: 
      int a;
      int b;

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

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

      public:
      B();
      ~B();
};
Run Code Online (Sandbox Code Playgroud)

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

小智 32

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

A * a = new B;
delete a;
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 它是未定义的,因为C++标准说它是. (6认同)
  • 虽然答案是正确的 - 你总是遵循标准 - 不提供任何下降解释 - 答案应该教会新程序员不要传播(或验证)经验丰富的程序员. (3认同)
  • @Autopopulated人们对此有一些非常奇怪的想法.任何人都会认为添加虚拟析构函数会增加一些巨大的开销.鉴于他们将产生的理性,以避免这样做. (3认同)
  • Terry:标准中未明确指定的任何内容或标准中未定义的任何内容都是未定义的.如果您执行未定义的操作,编译器可以随心所欲地执行任何操作.在这种情况下,它声明它未定义."尽管如此,这里有一些非常麻烦的事情.你的程序的行为是未定义的 - 你无法知道会发生什么......这意味着编译器可能会生成代码来做他们喜欢的事情:重新格式化你的磁盘,发送暗示性的电子邮件到你的老板,给你的竞争对手传真源代码,无论如何." - Scott Meyers,"Effective C++" (3认同)

AnT*_*AnT 19

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

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

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

后者通常表示为一个相当着名的良好实践指南:如果您的类至少有一个虚拟方法,那么也可以将析构函数设置为虚拟.虽然从形式上来看,虚拟析构函数可能并不是真正需要的,但它仍然是一个非常好的指南.

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

  • @Eli Bendersky:是的,确切地说.当然,除此之外,在层次结构的最底层定义一个显式的空(甚至纯)虚拟析构函数是完全足够的.所有其他析构函数将自动变为虚拟,即使它们是由编译器隐含定义的.也就是说,你没有*明确*在*every*class中定义一个空的析构函数.只是基地就够了. (3认同)