有没有具体的理由使用非虚拟析构函数?

Sha*_*ain 20 c++ language-design virtual-destructor

据我所知,任何指定具有子类的类都应该使用虚拟析构函数声明,因此在通过指针访问类实例时可以正确销毁它们.

但为什么甚至可以用非虚析构函数声明这样的类?我相信编译器可以决定何时使用虚拟析构函数.那么,它是一个C++设计监督,还是我错过了什么?

Mat*_* M. 19

有没有具体的理由使用非虚拟析构函数?

是的,有.

主要是,它归结为性能.无法内联虚函数,而必须首先确定要调用的正确函数(这需要运行时信息),然后调用该函数.

在性能敏感的代码中,无代码和"简单"函数调用之间的区别可能会有所不同.与许多语言不同,C++并不认为这种差异是微不足道的.

但为什么甚至可以用非虚析构函数声明这样的类?

因为很难知道(对于编译器)类是否需要虚拟析构函数.

在以下情况下需要虚拟析构函数:

  • 你调用delete指针
  • 通过基类到派生对象

当编译器看到类定义时:

  • 它无法知道你打算从这个类派生 - 毕竟你可以从没有虚方法的类派生
  • 但更令人生畏的是:它无法知道你打算delete在这个课上调用

很多人以为多态性需要newing实例,这只是纯粹缺乏想象力:

class Base { public: virtual void foo() const = 0; protected: ~Base() {} };

class Derived: public Base {
  public: virtual void foo() const { std::cout << "Hello, World!\n"; }
};

void print(Base const& b) { b.foo(); }

int main() {
  Derived d;
  print(d);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不需要为虚拟析构函数付费,因为在销毁时没有涉及多态性.

最后,这是一个哲学问题.在可行的情况下,C++默认选择性能和最小服务(主要的例外是RTTI).


关于警告.可以利用两个警告来发现问题:

  • -Wnon-virtual-dtor(gcc,Clang):只要具有虚函数的类没有声明虚析构函数,就会发出警告,除非生成基类中的析构函数protected.这是一个悲观的警告,但至少你不会错过任何东西.

  • -Wdelete-non-virtual-dtor(Clang,移植到gcc):警告只要delete在指向具有虚函数但没有虚析构函数的类的指针上调用,除非标记了类final.它的误报率为0%,但警告"迟到"(可能是几次).