c++ - 非多态基类中的析构函数

标签 c++ polymorphism destructor

考虑这段代码:

class A {
  public:
    void fun() {}
};

class B : public A {
  public:
    void fun() {}
};

int main()
{
    A *p = new B;

    delete p;
}

A 类和 B 类不是多态的,并且两个类都没有声明析构函数。如果我使用 g++ -Wall 编译这段代码,GCC 编译器会愉快地编译代码。

但是,如果我将 virtual 添加到 A 中的 void fun(),编译器会发出此警告:“正在删除多态类类型‘A’的对象,它具有非虚拟析构函数可能会导致未定义的行为”。

我非常清楚使用非虚拟析构函数的危险。但是上面的代码让我想知道两件事:

  1. 当我根本不使用析构函数时,为什么需要在基类中编写一个空的虚拟析构函数?
  2. 如果基类不包含其他虚函数,为什么不需要空虚析构函数?

编辑

看来我需要澄清困扰我的事情:

上面的代码没有声明析构函数。

如果我声明一个虚函数,编译器会提示缺少虚析构函数。我的结论是:如果该类是多态的,如果 delete p 要正常工作,我需要编写一个虚拟析构函数。

但是如果我没有声明虚函数(如上面的初始示例),编译器不会提示缺少虚析构函数。我的结论是:如果类不是多态的,我不需要编写虚拟析构函数,delete p 无论如何都会正常工作。

但最后一个结论在我看来直觉上是错误的。这是错的吗?编译器应该在这两种情况下都提示吗?

最佳答案

根据 PaulMcKenzie 和 KerrekSB 的评论,这里是对原帖中两个问题的回答:

  1. 类总是有一个析构函数,即使程序员没有明确地写一个。为了防止系统自动生成非虚拟析构函数,需要声明一个空的虚拟析构函数。
  2. 在提供的示例代码中,您确实需要一个虚析构函数,即使类中没有其他虚函数也是如此。 GCC 在这种情况下没有提示的事实可能是编译器中的一个错误(或者至少是一个缺点)。

这方面的背景可以在 C++11 标准的 §5.3.5 中找到,其中说,“如果要删除的对象的静态类型与其动态类型不同,则静态类型应为基类要删除的对象的动态类型的类,静态类型应具有虚拟析构函数,否则行为未定义。” (斜体是我的。)

关于c++ - 非多态基类中的析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22881085/

相关文章:

c++ - 如何找到从未调用过的函数

c# - 访问基类 C# 中的隐藏属性

java - 从不在父类中的java子类调用方法

c++ - 我如何*不*删除析构函数中的成员?

c++ - C++中的循环链表的析构函数?

c# - 无需安装的 C++ 数据库访问

c++ - 参数引用有物理变量吗?

c++ - 在指针类中引用虚函数时出现段错误

c++ - 我是否应该假设一个对象的析构函数在从 STL 容器中移除后立即被调用?

C++ 使用带任务列表的命令提示符扫描进程 ID