编译器如何处理派生析构函数中的 base class 析构函数调用?

How does the compiler handle base class destructor calls in the derived destructor?

出于好奇,我尝试做类似下面示例的操作,看看编译器是否给我警告,而不是调用一个最终导致堆栈溢出的无限循环。我想也许有一种不同于仅仅调用普通函数或方法的行为。但事实并非如此。对此是否有特殊解释,或者它只是作为普通函数调用处理,因为我通过使用 this 运算符明确调用基本 class 析构函数?

示例:

class A {
  virtual ~A();
};

class B : A {
  virtual ~B() { this->~A(); }
};

@M.M的评论中了。您正在两次调用析构函数。这是未定义的行为,任何事情都可能发生,包括您观察到的行为。

(实际上,很可能其中一个析构函数调用修改了对象的 vptr,这意味着后续的析构函数调用不再转到最派生的对象。但这只是一个猜测。)

正确的做法是不要手动调用析构函数。

调用派生的 class 虚拟析构函数导致调用基 class 析构函数。但反之则不然。

派生 class 中的虚拟析构函数总是首先调用父 class 析构函数,递归顺序使得最 "ancestral" base-class' 析构函数将被调用,然后是第二大-"ancestral",等等。想象一下,Child继承自Parent,Parent继承自GrandParent。 Child class' 的析构函数实际上会调用 GrandParent 的析构函数,然后是 Parent 的析构函数,然后是 Child 的析构函数。

事实上,您派生的 class 构造函数也以相同的递归顺序调用它们的父 class 构造函数。您必须将派生的 class 想象成 "layer cake":每个继承实例都会为您的对象添加一层。所以Childclass有3层{GrandParent,Parent,Child},每一层的construction/destruction由对应的class.

处理

您正在尝试的将尝试调用父析构函数两次,这是个坏主意。通常您不必显式调用析构函数,除非您重载了 new 运算符。有关详细信息,请参阅此答案:Is calling destructor manually always a sign of bad design?