多重继承的构造函数会被多次调用吗?构造函数是按什么顺序调用的?这取决于继承列表中的顺序吗?
这里有一个例子(这只是为了让情况变得清晰,没有实际的例子)。
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()
?
发布于 2011-09-13 17:21:58
按照您编写的方式,Derived
有两个不同于的Base
类型的子对象,每个子对象都从各自的DerivedBaseXXX
构造函数中调用它们自己的构造函数,它是DerivedBaseXXX
的子对象。调用的顺序遵循声明的顺序。
相反,如果声明DerivedBaseXXX : virtual public Base
,那么只有一个 Base
子对象,并且它的构造函数是从派生最多的对象中调用的,即从Derived
对象中调用。
(更详细地解释:一个(可能是单继承的)类是通过首先1)调用基类的构造函数,然后2)按声明的顺序调用所有成员对象的构造函数,最后3)执行构造函数主体来构造的。这是递归应用的,对于多重继承,您只需按照声明继承的顺序调用基类的所有构造函数来替换(1)。只有虚拟继承才会在这里增加一层真正的额外复杂性。)
发布于 2011-09-13 17:20:16
继承层次结构的构造函数调用顺序为:
Base()
DerivedBaseTwo()
Base()
DerivedBaseOne()
Derived()
顺序确实是定义良好的,并且取决于您提到基类的派生的顺序以及在类中为成员声明成员的顺序。(请参阅下面的C++标准中的参考。)
是否会调用Base()构造函数两次?
是的
Base()
类构造函数在这里被调用了两次,因为有两个类DerivedBaseTwo()
和DerivedBaseOne()
派生自它,所以基类构造函数被调用一次。您的Derived
类有两个不同的Base
子对象,它们通过多个路径(一个通过DerivedBaseOne()
,另一个通过DerivedBaseTwo()
)。
具有多重继承的类的层次结构是不寻常的,这会导致一个称为的问题。为了避免这个问题,C++引入了的概念。
参考资料:
C++03标准: 12.6.2/5,初始化库和成员
初始化应按以下顺序进行:
-首先,并且仅对于下面描述的最多派生类的构造函数,虚拟基类应该按照它们在基类的有向无循环图的深度优先从左向右遍历时出现的顺序进行初始化,其中“从左到右”是基类名称在派生类基说明符列表中的出现顺序。
-然后,直接基类应该按照它们在base-specifier-list中出现的声明顺序进行初始化(不管mem-initializers的顺序如何)。
-然后,应该按照类定义中声明的顺序对非静态数据成员进行初始化(同样,不管mem-initializers的顺序如何)。
-最后,执行构造函数的主体。
发布于 2011-09-13 17:21:58
答案是: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
是在创建其他所有内容之后创建的。
此外,对于多重继承,请注意Diamond Inheritance Problem
https://stackoverflow.com/questions/7405839
复制