c++ - 使用非虚拟析构函数有什么具体原因吗?

标签 c++ language-design virtual-destructor

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

但是为什么甚至可以用非虚拟析构函数声明这样的类呢?我相信编译器可以决定何时使用虚拟析构函数。那么,这是 C++ 设计疏忽,还是我遗漏了什么?

最佳答案

Are there any specific reasons to use non-virtual destructors?

是的,有。

主要归结为性能。虚函数不能被内联,相反,您必须首先确定要调用的正确函数(这需要运行时信息),然后再调用该函数。

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

But why it's even possible to declare such class with non-virtual destructor?

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

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

  • 您在指针上调用 delete
  • 通过基类到派生对象

当编译器看到类定义时:

  • 它不知道你打算从这个类派生——你毕竟可以从没有虚拟方法的类派生
  • 但更可怕的是:它不知道你打算在这个类上调用 delete

许多人认为多态性需要更新实例,这只是缺乏想象力:

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);
}

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

归根结底,这是一个哲学问题。在可行的情况下,C++ 默认选择性能和最少的服务(主要的异常(exception)是 RTTI)。


关于警告。有两个警告可以用来发现问题:

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

  • -Wdelete-non-virtual-dtor(Clang,也移植到 gcc):每当调用 delete 时发出警告指向具有虚函数但没有虚析构函数的类的指针,除非该类被标记为 final。它的误报率为 0%,但会发出“迟到”的警告(可能会多次)。

关于c++ - 使用非虚拟析构函数有什么具体原因吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8697866/

相关文章:

c++ - 如果无效,如何重复用户输入的电子邮件

c++ - 用 C++ 循环构建三角形

C 函数调用后跟逗号分隔符

java - 好的开源软件来分析

c++ - 从单 View 图像重建立体图像

python - "Least Astonishment"和可变默认参数

c++ - 我可以在 C++ 中做/模仿这样的事情(部分覆盖)吗?

c++ - 类 COM 接口(interface)警告非虚拟析构函数

c++ - std::enable_shared_from_this,非虚析构函数和公共(public)继承

c++ - 多态放置的东西的析构函数