全面解析C++中的析构函数

2020-01-06 14:25:24王旭

具有块范围的本地(自动)对象超出范围。
临时对象的生存期结束。
程序结束,并且存在全局或静态对象。
使用析构函数的完全限定名显式调用了析构函数。(有关详细信息,请参阅显式析构函数调用。)
前面的列表中所述的情况将确保所有对象均可通过用户定义的方法进行销毁。
如果基类或数据成员有一个可访问的析构函数,并且派生类未声明析构函数,则编译器将生成一个析构函数。此编译器生成的析构函数将为派生类型的成员调用基类析构函数和析构函数。默认析构函数是公共的。

析构函数可以随意调用类成员函数和访问类成员数据。从析构函数调用虚函数时,调用的函数是当前正在销毁的类的函数。
析构的顺序
当对象超出范围或被删除时,其完整析构中的事件序列如下所示:
将调用该类的析构函数,并且会执行该析构函数的主体。
按照非静态成员对象的析构函数在类声明中的显示顺序的相反顺序调用这些函数。用于这些成员的构造的可选成员优化列表不影响构造或析构的顺序。
非虚拟基类的析构函数以声明的相反顺序被调用。
虚拟基类的析构函数以声明的相反顺序被调用。


// order_of_destruction.cpp
#include <stdio.h>

struct A1   { virtual ~A1() { printf("A1 dtorn"); } };
struct A2 : A1 { virtual ~A2() { printf("A2 dtorn"); } };
struct A3 : A2 { virtual ~A3() { printf("A3 dtorn"); } };

struct B1   { ~B1() { printf("B1 dtorn"); } };
struct B2 : B1 { ~B2() { printf("B2 dtorn"); } };
struct B3 : B2 { ~B3() { printf("B3 dtorn"); } };

int main() {
  A1 * a = new A3;
  delete a;
  printf("n");

  B1 * b = new B3;
  delete b;
  printf("n");

  B3 * b2 = new B3;
  delete b2;
}

输出:


A3 dtor
A2 dtor
A1 dtor

B1 dtor

B3 dtor
B2 dtor
B1 dtor

虚拟基类
按照与虚拟基类在定向非循环图形中显示的顺序的相反顺序调用这些虚拟基类的析构函数(深度优先、从左到右、后序遍历)。下图描述了继承关系图。

全面解析C++中的析构函数

演示虚拟基类的继承关系图
下面列出了图中显示的类的类头。