Base class 没有析构函数,但是 derived class 有。我是否需要寻找与堆无关的任何陷阱?

Base class has no destructor, but derived class does. Do I need to look for any pitfalls that DON'T relate to the heap?

在继承方面,我了解到建议您的 classes 的析构函数是虚拟的,因此除了任何派生的析构函数之外,基础 class 的析构函数也会被正确调用。但是,我想知道在以下场景中是否存在与派生对象相关的堆栈相关问题。

假设我们有一个 Base class 没有析构函数(无论出于何种原因):

class Base{};

和一个确实有析构函数的派生 class:

class Derived : public Base
{
  ~Derived(){}
};

主要是...:

int main()
{
  Derived a;
  return 0;
}

我是否 运行 遇到任何来自 Base class 没有析构函数的问题?我最初的猜测是编译器只会为 Base class 生成一个默认的析构函数。同样,我的问题主要与堆栈而不是动态内存有关:是否有任何奇怪的情况我需要注意以避免调用 Derived 析构函数而 Base 析构函数没有被调用?

你的基础 class 有一个隐式析构函数。一切都会好起来的。

虚拟基 class 析构函数用于允许派生构造函数在通过指针或对基 class 的引用进行析构时 运行。所以在你的情况下,这将是不安全的:

void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);

但这绝对安全:

void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);

您想到的规则是,如果您通过指向其基类型之一的指针删除派生类型的对象,并且该基类型没有虚拟析构函数,则行为是未定义的。此处的代码不会删除任何内容,因此该规则不适用。

为了确保安全,每个析构函数(隐式或显式)至少是以下之一就足够了:

  • virtual(对于base classes,如果你需要通过base class指针删除子class实例)
  • protected(确保不可能通过基class指针尝试删除)
  • final(实际上是class的一个属性,避免了subclasses的全部可能性)。

有一些罕见的边缘情况可以安全地调用析构函数,但它们通常是糟糕设计的标志,如果您设法遇到其中一个,则很容易避免。

顺便说一句,请注意 std::shared_ptr 类型擦除其删除器,因此即使 Base 没有 public 析构函数,std::shared_ptr<Base> 也能正常工作。