多重继承的构造函数是否被多次调用?

发布于 2024-12-04 12:33:48 字数 493 浏览 0 评论 0原文

多重继承的构造函数是否被多次调用?构造函数的调用顺序是什么?这取决于继承列表中的顺序吗?

这是一个例子(只是为了说明情况,不是现实生活中的例子)。

class Base {};
class DerivedBaseOne : public Base {};
class DerivedBaseTwo : public Base {};
class Derived : public DerivedBaseTwo, public DerivedBaseOne 
{};

//somewhere in the code, is Base() called two times here?
Derived * foo = new Derived();

Base() 构造函数是否被调用了两次?构造函数的调用顺序是什么?先有基地?还是先使用 DerivedBaseOne()DerivedBaseTwo()

Are multiple-inherited constructors called multiple times? And in what order are constructors called? Does this depend on the order in the inheritance list?

Here is an example (it's only for making the situation clear, no real-life example).

class Base {};
class DerivedBaseOne : public Base {};
class DerivedBaseTwo : public Base {};
class Derived : public DerivedBaseTwo, public DerivedBaseOne 
{};

//somewhere in the code, is Base() called two times here?
Derived * foo = new Derived();

Is the Base() constructor called twice? And in what order are the constructors called? Base first? Or DerivedBaseOne() or DerivedBaseTwo() first?

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

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

发布评论

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

评论(3

萝莉病 2024-12-11 12:33:48

继承层次结构的构造函数调用顺序将是:

Base()  
DerivedBaseTwo()  
Base()
DerivedBaseOne()  
Derived()

该顺序确实是明确定义的,并且取决于您提到基类派生的顺序以及您在类中声明成员的成员的顺序。 (请参阅下面的 C++ 标准参考。)

Base() 构造函数是否被调用两次?
YES

Base() 类构造函数在这里被调用两次,因为两个类 DerivedBaseTwo()DerivedBaseOne()从它派生,因此每个基类构造函数都会被调用一次。您的 Derived 类通过多个路径有两个不同的 Base 子对象(一个通过 DerivedBaseOne() ,另一个通过 DerivedBaseTwo()代码>)。

具有多重继承的类的层次结构是不寻常的,它会导致一个称为菱形继承的问题问题。为了避免这个问题,C++ 引入了 虚拟基类


参考:

C++03标准:12.6.2/5,初始化基类和成员

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

——首先,并且仅对于如下所述的最派生类的构造函数,虚拟基类应按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“从左到右”是派生类基说明符列表中基类名称的出现顺序。

——然后​​,直接基类应按照它们出现在基说明符列表中的声明顺序进行初始化(无论 mem 初始化程序的顺序如何)。

——然后​​,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(同样无论 mem 初始化程序的顺序如何)。

——最后,构造函数的主体被执行。

The order of constructor calls for your inheritance hierarchy will be:

Base()  
DerivedBaseTwo()  
Base()
DerivedBaseOne()  
Derived()

The order is indeed well-defined and depends on the order in which you mention the derivation for base classes and the order in which you declare members in the class for members. (See the reference from the C++ Standard below.)

Does the Base() constructor get called twice?
YES

The Base() class constructor gets called here twice, because two classes DerivedBaseTwo() and DerivedBaseOne() derive from it, so the base class constructor gets called once for each of them. Your Derived class has two distinct Base subobjects through multiple paths (one through DerivedBaseOne() and the other though DerivedBaseTwo()).

The hierarchy of classes you have with multiple inheritance is unusual and it leads to a problem called the Diamond Shaped Inheritance Problem. To avoid this problem C++ introduces the concept of Virtual base class.


Reference:

C++03 Standard: 12.6.2/5, Initializing bases and members

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.

将军与妓 2024-12-11 12:33:48

按照您的编写方式,Derived两个Base 类型的不同子对象,每个子对象都从各自的 DerivedBaseXXX 调用自己的构造函数 构造函数,它是其子对象。调用顺序遵循声明顺序。

相比之下,如果您声明 DerivedBaseXXX : virtual public Base,则只有 一个 Base 子对象,并且从最派生的子对象调用其构造函数对象,即来自 Derived 对象。

(更详细地解释一下:(可能是单继承)类的构造方法是:首先 1)调用基类的构造函数,然后 2)按照声明的顺序调用所有成员对象的构造函数,最后 3)执行构造函数体。这适用于递归,对于多重继承,您只需按照声明继承的顺序调用所有基类的构造函数来替换 (1)。只有虚拟继承在这里增加了真正的额外复杂性。)

The way you write it, Derived has two distinct subobjects of type Base, and each gets their own constructor called from the respective DerivedBaseXXX constructor of which it is the subobject. The order of calls follows the order of declaration.

By contrast, of you declare DerivedBaseXXX : virtual public Base, then there is only one Base subobject, and its constructor is called from the most derived object, i.e. from the Derived object.

(To explain in a bit more detail: A (possibly singly-inheriting) class is constructed by first 1) calling the base class's constructor, then 2) calling the constructors of all member objects in their order of declaration, and finally 3) executing the constructor function body. This applies recursively, and for multiple inheritance, you just replace (1) by calling all the base class's constructors in the order in which the inheritance was declared. Only virtual inheritance adds a genuine extra layer of complication here.)

吐个泡泡 2024-12-11 12:33:48

这个问题的答案是:http://www.parashift。 com/c++-faq-lite/multiple-inheritance.html#faq-25.14

最先执行的构造函数是层次结构中任何位置的虚拟基类。它们按照在基类图的深度优先从左到右遍历中出现的顺序执行,其中从左到右指的是基类名称的出现顺序。

由于您的多重继承声明首先列出了 DerivedBaseTwo,因此其构造顺序将在 DerivedBaseOne 之前执行。

因此,在您的 Derived 类中,首先创建 DerivedBaseTwo 及其链,即:

1 - Base 然后是 DerivedBaseTwo

然后 DerivedBaseOne 及其链:

2 - Base 然后 DerivedBaseOne

然后:

3 - Derived 在一切之后创建 别的。

另外,对于多重继承,请注意钻石继承问题

This is answered in: http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.14

The very first constructors to be executed are the virtual base classes anywhere in the hierarchy. They are executed in the order they appear in a depth-first left-to-right traversal of the graph of base classes, where left to right refer to the order of appearance of base class names.

Since your multiple inheritance declaration lists DerivedBaseTwo first, its construction order will be executed before DerivedBaseOne's.

So in your Derived class, DerivedBaseTwo and its chain is created first, that is:

1 - Base then DerivedBaseTwo

And then DerivedBaseOne and its chain:

2 - Base then DerivedBaseOne

And then:

3 - Derived is created after everything else.

Also, with multiple inheritance be mindful of the Diamond Inheritance Problem

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