使用虚拟破坏顺序

发布于 2024-09-14 10:27:36 字数 43 浏览 10 评论 0原文

有人可以帮助我使用虚拟函数时的破坏顺序吗?是从基类开始,然后是派生类吗?

Can some one please help what the order of destruction is when I am using virtual functions. Does it start with the base class and then derived class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

猫烠⑼条掵仅有一顆心 2024-09-21 10:27:36

由于我没有看到虚拟函数如何更改任何对象的销毁顺序,因此我假设您指的是虚拟继承中的基类和数据成员的销毁顺序继承 场景。

子对象构造

  1. 基类从最基础到最派生构造;
  2. 多个基类按照其声明为基类的顺序构造;
  3. 虚拟基类先于所有其他构建,它​​们之间遵守上述两条规则;
  4. 数据成员是在执行封闭对象的构造函数主体之前按照声明的顺序构造的。

破坏构造完全相反,所以你只需要记住上面的内容即可。

然而,上述四个规则是按这个顺序排列的,因为这是有道理的,如果你理解为什么这个顺序有意义,你甚至不必记住这四个规则,而是可以从你的理解中推断出它们(就像我刚才所做的那样)。因此,让我们检查一下该顺序:

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

Since I don't see how virtual function change any objects' destruction order, I assume you're referring to the order of destruction for base classes and data members in a virtual inheritance scenario.

Sub-objects are constructed

  1. base classes are constructed from most base to most derived;
  2. multiple base classes are constructed in the order of their declaration as base classes;
  3. virtual base classes are constructed before all others, amongst themselves adhering to the above two rules;
  4. data members are constructed before the enclosing object's constructor's body is executed, in order of their declaration.

Destruction is simply the opposite of construction, so you only need to memorize the above.

However, the above four rules are in that order because that makes sense, and if you understand why this order makes sense, you will not even have to memorize those four rules, but can infer them from your understanding (as I just did). So let's examine that order:

  • You might want to use whatever service the base class provide from a derived class' constructor. Of course, you cannot use a (base) class object before it's actually constructed. Therefore, when a derived class is constructed, the base class needs to be already constructed. (Incidentally, this also explains why the virtual function dispatching doesn't fully work from within constructors: When a sub-object is constructed, only the sub-objects of base classes are already constructed; the derived classes' sub-objects are not yet constructed. Therefore a call to a virtual function must not be dispatched to a derived class. As always, destructors are the same, just backwards.)
  • With multiple base classes being equal siblings, some order had to be picked arbitrarily. Ultimately, the order of declaration is the most simple one to use. Data members, which also are equal siblings, follow the same (more or less arbitrary) in-order-of-declaration rule.
  • Virtual base classes are strange beasts. Because there will always only be one sub-object of a virtual base class, there's that special rule which says it always needs to be constructed first, right from the most derived class' constructor. (Which is why virtual base classes work best as abstract base classes with no data and only default constructors.)
两个我 2024-09-21 10:27:36

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

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

一般来说,这将是:

A) 从最派生的类开始。
B) 递归地重复以下操作。

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

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

Assuming you have correctly declared your destructor as virtual.

Then destruction is done in the exact opposite order of construction.

In General this will be:

A) Start in the most derived class.
B) Repeat the following recursively.

1) Execute the destructor code.
2) Execute the destructor of each member (in reverse order of creation)
3) Execute the destructor of the parent class. (if more than one in reverse order of creation)

If you use virtual inheritance though then things are slightly different as the order of base class construction is not the same as normal. BUT The order of destruction is ALWAYS the reverse of the order of construction.

情域 2024-09-21 10:27:36

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

在图中,编号较小的节点第一个被构造,最后被破坏。

The destruction order is the construction order backwards. I've recently made a small tool to display the construction order for any hierarchy. Look here:

In the diagrams, the nodes with the smaller numbers are constructed first and destructed last.

赠佳期 2024-09-21 10:27:36

第 12.6.2/5 节:

初始化应按以下顺序进行:

  • 首先,且仅适用于最底层派生类的构造函数:
    如下所述,虚拟基类应在
    它们在深度优先从左到右遍历时出现的顺序
    基类的有向无环图,其中“从左到右”是
    基类名称在派生类中的出现顺序
    基本说明符列表。
  • 然后,直接基类将被初始化
    按照它们出现在基本说明符列表中的声明顺序
    (无论内存初始化器的顺序如何)。
  • 然后,非静态
    数据成员应按照声明的顺序进行初始化
    类定义(同样不管顺序
    内存初始化器)。 — 最后,执行构造函数的主体。

[注意:声明顺序必须确保基数和
成员子对象以相反的顺序被销毁
初始化。 ]

Section 12.6.2/5:

Initialization shall proceed in the following order:

  • First, and only for the constructor of the most derived class as
    described below, virtual base classes shall be initialized in the
    order they appear on a depth-first left-to-right traversal of the
    directed acyclic graph of base classes, where “left-to-right” is the
    order of appearance of the base class names in the derived class
    base-specifier-list.
  • Then, direct base classes shall be initialized
    in declaration order as they appear in the base-specifier-list
    (regardless of the order of the mem-initializers).
  • Then, nonstatic
    data members shall be initialized in the order they were declared in
    the class definition (again regardless of the order of the
    mem-initializers). — Finally, the body of the constructor is executed.

[Note: the declaration order is mandated to ensure that base and
member subobjects are destroyed in the reverse order of
initialization. ]

最近可好 2024-09-21 10:27:36

这与构造函数相反。故先推导。

It is the opposite way as the constructors. So derived first.

东北女汉子 2024-09-21 10:27:36

从下到上的破坏顺序。 (从派生到基础)

简短回答:正好相反
构造函数顺序。

长答案:假设“最
派生”类是D,意思是
原本的实际物体
创建的是 D 类,并且 D
继承乘法(和非虚拟)
从B1和B2。子对象
对应于最派生类 D
首先运行,然后是 dtors
它的非虚拟基类
反向声明顺序。因此
析构函数顺序为 D、B2、B1。
该规则递归应用;为了
例如,如果 B1 继承自 B1a 并且
B1b和B2继承自B2a和B2b,
最终顺序是D、B2、B2b、B2a,
B1、B1b、B1a。

请参阅 c++ 常见问题解答第 25 节

Order of destructions if from the bottom up. (from derived to base)

Short answer: the exact opposite of
the constructor order.

Long answer: suppose the "most
derived" class is D, meaning the
actual object that was originally
created was of class D, and that D
inherits multiply (and non-virtually)
from B1 and B2. The sub-object
corresponding to most-derived class D
runs first, followed by the dtors for
its non-virtual base classes in
reverse declaration-order. Thus the
destructor order will be D, B2, B1.
This rule is applied recursively; for
example, if B1 inherits from B1a and
B1b, and B2 inherits from B2a and B2b,
the final order is D, B2, B2b, B2a,
B1, B1b, B1a.

See the c++ faq section 25

临风闻羌笛 2024-09-21 10:27:36

虚拟函数对销毁顺序没有影响,而虚拟基类则不同。

如果没有虚拟基类,派生类总是在其基类之前被销毁;这是它们构建的相反顺序。

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

Virtual functions make no difference to the order of destruction, virtual base classes, on the other hand, do.

Without virtual base classes, derived classes are always destroyed before their base classes; this is the reverse order in which they are constructed.

For the most derived class, virtual base classes are constructed first, before other base classes and before the most derived class itself. Destruction happens in the reverse order. This means that a virtual base may be destroyed after a class that derives virtually from it, if that class is not the most derived class being destroyed. This can never happen for direct base classes.

凝望流年 2024-09-21 10:27:36

首先是派生的,然后是基数。非虚拟案例没有区别。

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

例如,假设 Derived 是从 Base 派生的,并且您使用以下行分配 Derived:

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

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

First the derived, then the base. No difference wrt the non-virtual cases.

Additional note. When you have inheritance and virtual methods, you have to declare destructors as virtual, otherwise you can have undefined behavior at deletion.

Example, suppose Derived is derived from Base, and you allocate Derived with the following line:

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

If this case occurs in your code, and Base has no virtual destructor, the resulting behavior is undefined. Typically, only the destructor of Base will be called. The destructor of Derived will not be called, because you are calling delete on a Base pointer. However, the program might crash instead. Once you are in the realm of undefined behavior, all bets are off and your running code is doomed. To prevent chaos the Base destructor must be virtual.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文