C++ 使用虚拟仪器的销毁顺序

C++ 使用虚拟仪器的销毁顺序,c++,destructor,virtual-destructor,C++,Destructor,Virtual Destructor,当我使用虚拟函数时,有人能告诉我销毁的顺序吗。它是从基类开始,然后是派生类吗?虚拟函数对销毁顺序没有影响,而虚拟基类则是这样 没有虚拟基类,派生类总是在基类之前被销毁;这与它们的构造顺序相反 对于最派生的类,首先构造虚拟基类,然后构造其他基类,然后构造最派生的类本身。破坏按相反的顺序发生。这意味着,如果虚拟基类不是被销毁的派生最多的类,那么虚拟基类可能会在虚拟基类派生的类之后被销毁。对于直接基类,这种情况永远不会发生。与构造函数相反。因此首先派生。假设您已正确地将析构函数声明为虚拟 然后按照与构

当我使用虚拟函数时,有人能告诉我销毁的顺序吗。它是从基类开始,然后是派生类吗?

虚拟函数对销毁顺序没有影响,而虚拟基类则是这样

没有虚拟基类,派生类总是在基类之前被销毁;这与它们的构造顺序相反


对于最派生的类,首先构造虚拟基类,然后构造其他基类,然后构造最派生的类本身。破坏按相反的顺序发生。这意味着,如果虚拟基类不是被销毁的派生最多的类,那么虚拟基类可能会在虚拟基类派生的类之后被销毁。对于直接基类,这种情况永远不会发生。

与构造函数相反。因此首先派生。

假设您已正确地将析构函数声明为虚拟

然后按照与构造完全相反的顺序进行破坏

一般来说,这将是: A) 从最派生的类开始。
B) 递归地重复以下步骤

1) 执行析构函数代码。
2) 执行每个成员的析构函数(与创建顺序相反)
3) 执行父类的析构函数。(如果按创建的相反顺序有多个)


但如果使用虚拟继承,则情况会略有不同,因为基类构造的顺序与正常情况不同。但破坏的顺序总是与构造的顺序相反。

如果从下至上,则破坏的顺序。(从导出到基)

简短的回答:正好相反 构造函数命令

长答案:假设“最 派生”类是D,表示 原来是的实际对象 创建的是类D,而该类D 继承乘法(和非虚拟) 从B1和B2开始。子对象 对应于大多数派生类D 首先运行,然后是的DTOR 它的非虚拟基类在 反向申报顺序。因此 析构函数顺序为D、B2、B1。 这个规则是递归应用的;对于 例如,如果B1继承自B1a和 B1b和B2继承自B2a和B2b, 最后的订单是D,B2,B2b,B2a, B1,B1b,B1a


请参见

销毁顺序是向后的构造顺序。我最近制作了一个小工具来显示任何层次结构的构造顺序。看这里:


在图中,数字较小的节点先构造,然后分解

首先是派生节点,然后是基础节点。非虚拟病例无差异

补充说明。当您有继承和虚拟方法时,必须将析构函数声明为虚拟的,否则在删除时可能会有未定义的行为

例如,假设“派生”是从基派生的,并使用以下行分配“派生”:

Base *o = new Derived();
delete(o);

如果这种情况发生在代码中,并且Base没有虚拟析构函数,则结果行为是未定义的。通常,只调用Base的析构函数。将不会调用派生的析构函数,因为您正在对基指针调用delete。但是,程序可能会崩溃。一旦您进入了未定义行为的领域,所有的赌注都将落空,您正在运行的代码将注定失败。为了防止混乱,基本析构函数必须是虚拟的。

因为我看不到虚拟函数如何改变任何对象的销毁顺序,我假设您指的是虚拟继承中基类和数据成员的销毁顺序

子对象是构造的

  • 基类是从最基本到最派生的构造
  • 多个基类按照它们作为基类声明的顺序构造
  • 虚拟基类是在所有其他基类之前构建的,它们之间遵循上述两条规则
  • 数据成员是在执行封闭对象的构造函数体之前按照声明顺序构造的
  • 破坏只是构造的反面,所以你只需要记住上面的内容

    然而,以上四条规则是按顺序排列的,因为这是有意义的,如果你理解了为什么这个顺序是有意义的,你甚至不需要记住这四条规则,但可以从你的理解中推断出来(就像我刚才做的那样)。让我们来研究一下这个顺序:

    • 您可能希望使用基类从派生类的构造函数提供的任何服务。当然,在实际构造(基类)对象之前,不能使用它。因此,在构造派生类时,需要已经构造基类。(顺便说一句,这也解释了为什么虚拟函数调度不能从构造函数内部完全工作:当构造子对象时,只有基类的子对象已经被构造;派生类的子对象还没有被构造。因此,对虚拟函数的调用不能被调度到派生类s、 与往常一样,析构函数是相同的,只是向后。)
    • 由于多个基类是相等的兄弟类,因此必须任意选择某些顺序。最终,声明的顺序是最简单的。数据成员也是相等的同级成员,按照声明规则的顺序遵循相同的顺序(或多或少是任意的)
    • 虚拟基类是奇怪的野兽。因为一个虚拟基类总是只有一个子对象,所以有一个特殊的规则说它总是需要首先构造,就从最派生类的构造函数开始。(这就是为什么虚拟基类作为抽象基类工作得最好,没有数据,只有默认构造。)