当我使用虚拟功能时,有人可以帮助解决破坏的顺序。它是从基类开始,然后是派生类吗?
答案 0 :(得分:10)
由于我没有看到虚函数如何更改任何对象的销毁顺序,我假设您指的是虚拟 继承中基类和数据成员的销毁顺序 场景。
子对象 构建
销毁 与构建完全相反,因此您只需记住上述内容即可。
然而,上述四条规则是按顺序排列的,因为这是有道理的,如果你理解为什么这个顺序有意义,你甚至不必记住这四条规则,但可以从你的理解中推断它们(因为我只是所做的那样)。那么让我们检查一下这个顺序:
答案 1 :(得分:5)
假设您已将析构函数正确声明为虚拟。
然后以完全相反的构造顺序完成破坏。
A)从派生程度最高的班级开始 B)递归地重复以下步骤。
1)执行析构函数代码
2)执行每个成员的析构函数(按创建的相反顺序)
3)执行父类的析构函数。 (如果创建的顺序不止一个)
如果你使用虚拟继承,那么事情会略有不同,因为基类构造的顺序与正常情况不同。 但是破坏的顺序总是与施工顺序相反。
答案 2 :(得分:1)
销毁订单是向后的施工订单。我最近制作了一个小工具来显示任何层次结构的构造顺序。看这里:
在图表中,数字较小的节点构造为第一,并且最后 。
答案 3 :(得分:1)
第12.6.2 / 5节:
初始化应按以下顺序进行:
- 首先,仅适用于派生程度最高的类的构造函数 如下所述,虚拟基类应在中初始化 命令它们出现在深度优先从左到右的遍历中 基类的有向非循环图,其中“从左到右”是 派生类中基类名称的出现顺序 基说明符列表。
- 然后,应初始化直接基类 按声明顺序显示在base-specifier-list中 (无论mem-initializers的顺序如何)。
- 然后,非静止的 数据成员应按其声明的顺序进行初始化 类定义(再次无论顺序如何 MEM-初始化)。 - 最后,执行构造函数的主体。
[注意:声明命令的目的是确保基础和 成员子对象以相反的顺序销毁 初始化。 ]
答案 4 :(得分:0)
虚拟函数对破坏的顺序没有影响,另一方面,虚拟基类也没有区别。
没有虚拟基类,派生类总是在其基类之前被销毁;这是它们构造的相反顺序。
对于大多数派生类,首先构造虚拟基类,然后在其他基类之前和最派生类本身之前构造虚拟基类。销毁以相反的顺序发生。这意味着虚拟基础可能会在实际派生它的类之后被销毁,如果该类不是被销毁的最派生类。对于直接基类,这种情况永远不会发生。
答案 5 :(得分:0)
这与构造函数相反。首先派生出来。
答案 6 :(得分:0)
从下往上的破坏顺序。 (从派生到基础)
简短回答:恰恰相反 构造函数命令。
答案很长:假设“最多 派生的“阶级是D,意思是 最初的实际对象 创造了D级,D 继承乘法(和非虚拟) 来自B1和B2。子对象 对应于大多数派生的D类 首先运行,然后是dtors 它的非虚拟基类 反向申报单。就这样 析构函数顺序为D,B2,B1。 此规则以递归方式应用;对于 例如,如果B1继承自B1a和 B1b和B2继承自B2a和B2b, 最后的订单是D,B2,B2b,B2a, B1,B1b,B1a。
答案 7 :(得分:0)
首先派生,然后是基础。非虚拟案例没有区别。
补充说明。当你有继承和虚方法时,你必须将析构函数声明为虚拟,否则你可以删除未定义的行为。
示例,假设Derived派生自Base,并使用以下行分配Derived:
Base *o = new Derived();
delete(o);
如果您的代码中出现这种情况,并且Base没有虚拟析构函数,则结果行为是未定义的。通常,只会调用Base的析构函数。 Derived的析构函数不会被调用,因为你在Base指针上调用delete。但是,该程序可能会崩溃。一旦你处于未定义行为的领域,所有的赌注都会关闭,你的运行代码就会注定失败。为了防止混乱,Base析构函数必须是虚拟的。