[英]Order of calling constructors/destructors in inheritance
A little question about creating objects. 有关创建对象的一个小问题。 Say I have these two classes:
说我有这两节课:
struct A{
A(){cout << "A() C-tor" << endl;}
~A(){cout << "~A() D-tor" << endl;}
};
struct B : public A{
B(){cout << "B() C-tor" << endl;}
~B(){cout << "~B() D-tor" << endl;}
A a;
};
and in main I create an instance of B
: 在主我创建一个
B
的实例:
int main(){
B b;
}
Note that B
derives from A
and also has a field of type A
. 请注意,
B
派生自A
并且还具有类型A
的字段。
I am trying to figure out the rules. 我试图弄清楚规则。 I know that when constructing an object first calls its parent constructor, and vice versa when destructing.
我知道在构造对象时,首先调用其父构造函数,反之亦然。
What about fields ( A a;
in this case)? 字段(
A a;
在这种情况下)呢? When B
is created, when will it call A
's constructor? 创建
B
,何时会调用A
的构造函数? I haven't defined an initialization list, is there some kind of a default list? 我尚未定义初始化列表,是否存在某种默认列表? And if there's no default list?
如果没有默认列表? And the same question about destructing.
关于销毁的同样问题。
class
. class
。 If there are multiple base class
es then, construction starts with the left most base. class
则从最左侧的基class
开始构建。 ( side note : If there is a virtual
inheritance then it's given higher preference). virtual
继承,则它具有更高的优先级)。 class
itself is constructed class
本身被构造 Irrespective of the initializer list, the call order will be like this: 无论初始化列表如何,调用顺序都将如下所示:
class A
's constructor class A
的构造函数 class B
's field named a
(of type class A
) will be constructed class B
的名为a
(类型class A
的类型)的字段 class B
's constructor class B
的构造函数 Assuming there is not virtual/multiple inheritance (that complicates things quite a bit) then the rules are simple: 假设没有虚拟/多重继承(这使事情复杂化了很多),那么规则很简单:
One important thing to remember is that until step 4 the object is not yet an instance of its class, becuse it gains this title only after the execution of the constructor begins. 要记住的重要一件事是,在第4步之前该对象还不是其类的实例,因为该对象只有在构造函数的执行开始后才获得此标题。 This means that if there is an exception thrown during the constructor of a member the destructor of the object is not executed, but only already constructed parts (eg members or base classes) will be destroyed.
这意味着,如果在成员的构造函数期间引发异常,则不会执行对象的析构函数,而只会破坏已经构造的部分(例如,成员或基类)。 This also means that if in the constructor of a member or of a base class you call any virtual member function of the object the implementation called will be the base one, not the derived one.
这也意味着,如果在成员或基类的构造函数中调用对象的任何虚拟成员函数,则调用的实现将是基函数,而不是派生函数。 Another important thing to remember is that member listed in the initialization list will be constructed in the order they are declared in the class, NOT in the order they appear in the initialization list (luckily enough most decent compilers will issue a warning if you list members in a different order from the class declaration).
要记住的另一件重要事情是,初始化列表中列出的成员将按照在类中声明的顺序构造,而不是按照它们在初始化列表中出现的顺序构造(幸运的是,如果列出成员,大多数体面的编译器都会发出警告(与类声明的顺序不同)。
Note also that even if during the execution of constructor code the this
object already gained its final class (eg in respect to virtual dispatch) the destructor of the class is NOT going to be called unless the constructor completes its execution . 还要注意,即使在执行构造函数代码期间,
this
对象已经获得了其最终类(例如,关于虚拟调度),也不会调用该类的析构函数,除非构造函数完成其执行 。 Only when the constructor completes execution the object instance is a real first class citizen among instances... before that point is only a "wanna-be instance" (despite having the correct class). 只有当构造函数完成执行时,对象实例才是实例中真正的一等公民……在那之前,只有“想成为实例”(尽管具有正确的类)。
Destruction happens in the exact reverse order: first the object destructor is executed, then it loses its class (ie from this point on the object is considered a base object) then all members are destroyed in reverse declaration order and finally the base class destruction process is executed up to the most abstract parent. 销毁以完全相反的顺序发生:首先执行对象析构函数,然后丢失其类(即,从该点开始,该对象被视为基础对象),然后按相反的声明顺序销毁所有成员,最后销毁基类执行到最抽象的父级。 As for the constructor if you call any virtual member function of the object (either directly or indirectly) in a base or member destructor the implementation executed will be the parent one because the object lost its class title when the class destructor completed.
对于构造函数,如果您在基或成员析构函数中调用对象的任何虚拟成员函数(直接或间接),则执行的实现将是父函数,因为当类析构函数完成时,对象会丢失其类标题。
Base classes are always constructed before data members. 基类始终在数据成员之前构造。 Data members are constructed in the order that they are declared in the class.
数据成员按照在类中声明的顺序构造。 This order has nothing to do with the initialization list.
此顺序与初始化列表无关。 When a data member is being initialized, it will look through your initialization list for the parameters, and call the default constructor if there is no match.
初始化数据成员时,它将在初始化列表中查找参数,如果不匹配,则调用默认构造函数。 Destructors for data members are always called in the reverse order.
数据成员的析构函数始终以相反的顺序调用。
Base class constructor always executes first.so when you write a statement B b;
基类构造函数始终首先执行。因此,当您编写语句
B b;
the constructor of A
is called first and then the B
class constructor.therefore the output from the constructors will be in a sequence as follows: 首先调用
A
的构造函数,然后再调用B
类的构造函数,因此构造函数的输出将按以下顺序排列:
A() C-tor
A() C-tor
B() C-tor
#include<iostream>
class A
{
public:
A(int n=2): m_i(n)
{
// std::cout<<"Base Constructed with m_i "<<m_i<<std::endl;
}
~A()
{
// std::cout<<"Base Destructed with m_i"<<m_i<<std::endl;
std::cout<<m_i;
}
protected:
int m_i;
};
class B: public A
{
public:
B(int n ): m_a1(m_i + 1), m_a2(n)
{
//std::cout<<"Derived Constructed with m_i "<<m_i<<std::endl;
}
~B()
{
// std::cout<<"Derived Destructed with m_i"<<m_i<<std::endl;
std::cout<<m_i;//2
--m_i;
}
private:
A m_a1;//3
A m_a2;//5
};
int main()
{
{ B b(5);}
std::cout <<std::endl;
return 0;
}
The answer in this case is 2531. How constructor are called here: 在这种情况下,答案是2531。在这里如何调用构造函数:
The same-way Destructor is called: 相同的析构函数称为:
In this example, construction of m_A1 & m_A2 is irrelevant of order of initialization list order but their declaration order. 在此示例中,m_A1和m_A2的构造与初始化列表顺序的顺序无关,但与它们的声明顺序无关。
Output from the modified code is: 修改后的代码的输出为:
A() C-tor
A() C-tor
B() C-tor
~B() D-tor
~A() D-tor
~A() D-tor
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.