C++ 继承中调用构造函数/析构函数的顺序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7539282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Order of calling constructors/destructors in inheritance
提问by Bug
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)? When B
is created, when will it call A
's constructor? 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.
字段(A a;
在这种情况下)呢?什么时候B
创建,什么时候调用A
的构造函数?我还没有定义初始化列表,是否有某种默认列表?如果没有默认列表?关于破坏的同样问题。
回答by iammilind
- Construction always starts with the base
class
. If there are multiple baseclass
es then, construction starts with the left most base. (side note: If there is avirtual
inheritance then it's given higher preference). - Then the member fields are constructed. They are initialized in the order they are declared
- Finally, the
class
itself is constructed - The order of the destructor is exactly the reverse
- 建设总是从基地开始
class
。如果有多个基数,class
则从最左边的基数开始构建。(旁注:如果有virtual
继承,则给予更高的优先权)。 - 然后构造成员字段。它们按照声明的顺序进行初始化
- 最后,
class
自身被构建 - 析构函数的顺序正好相反
Irrespective of the initializer list, the call order will be like this:
无论初始化列表如何,调用顺序都将如下所示:
- Base
class A
's constructor class B
's field nameda
(of typeclass A
) will be constructed- Derived
class B
's constructor
- Base
class A
的构造函数 class B
将构造名为a
(类型class A
)的字段- Derived
class B
的构造函数
回答by 6502
Assuming there is not virtual/multiple inheritance (that complicates things quite a bit) then the rules are simple:
假设没有虚拟/多重继承(这使事情变得相当复杂),那么规则很简单:
- The object memory is allocated
- The constructor of base classes are executed, ending with most derived
- The member initialization is executed
- The object becomes a true instance of its class
- Constructor code is executed
- 分配对象内存
- 执行基类的构造函数,以大多数派生结束
- 执行成员初始化
- 该对象成为其类的真实实例
- 构造函数代码被执行
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. 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 (e.g. 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).
需要记住的一件重要事情是,在第 4 步之前,该对象还不是其类的实例,因为它只有在构造函数开始执行后才获得此称号。这意味着如果在成员的构造函数期间抛出异常,则不会执行对象的析构函数,而只会销毁已经构造的部分(例如成员或基类)。这也意味着,如果在成员或基类的构造函数中调用对象的任何虚拟成员函数,则调用的实现将是基函数,而不是派生函数。另一个要记住的重要事情是初始化列表中列出的成员将按照它们在类中声明的顺序构造,
Note also that even if during the execution of constructor code the this
object already gained its final class (e.g. in respect to virtual dispatch) the destructor of the class is NOT going to be called unless the constructor completes its execution. 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).
还要注意,即使在构造函数代码的执行过程中,this
对象已经获得了它的最终类(例如,关于虚拟分派),除非构造函数完成其执行,否则不会调用该类的析构函数。只有当构造函数完成执行时,对象实例才是实例中真正的一等公民……在那之前只是一个“想要成为的实例”(尽管有正确的类)。
Destruction happens in the exact reverse order: first the object destructor is executed, then it loses its class (i.e. 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.
析构以完全相反的顺序发生:首先执行对象析构函数,然后它失去它的类(即从这一点上对象被认为是基对象)然后以相反的声明顺序销毁所有成员,最后是基类销毁过程执行到最抽象的父级。至于构造函数,如果您在基或成员析构函数中调用对象的任何虚拟成员函数(直接或间接),则执行的实现将是父函数,因为在类析构函数完成时对象失去了类标题。
回答by Vaughn Cato
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.
基类总是在数据成员之前构造。数据成员按照它们在类中声明的顺序构造。这个顺序与初始化列表无关。当一个数据成员被初始化时,它会在你的初始化列表中查找参数,如果没有匹配则调用默认构造函数。数据成员的析构函数总是以相反的顺序调用。
回答by shubhendu mahajan
Base class constructor always executes first.so when you write a statement 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:
基类构造函数总是先执行。所以当你写一个语句时B b;
,A
首先调用的构造函数,然后是B
类构造函数。因此构造函数的输出将按如下顺序:
A() C-tor
A() C-tor
B() C-tor
回答by NEERAJ SWARNKAR
#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。 这里如何调用构造函数:
- B::A(int n=2) constructor is called
- B::B(5) constructor is called
- B.m_A1::A(3) is called
- B.m_A2::A(5) is called
- B::A(int n=2) 构造函数被调用
- B::B(5) 构造函数被调用
- B.m_A1::A(3) 被调用
- B.m_A2::A(5) 被调用
The same-way Destructor is called:
相同的析构函数被称为:
- B::~B() is called. i.e m_i = 2, which decrement m_i to 1 in A.
- B.m_A2::~A() is called. m_i = 5
- B.m_A1::~A() is called. m_i = 3 4 B::~A() is called., m_i = 1
- B::~B() 被调用。即 m_i = 2,即在 A 中将 m_i 减至 1。
- B.m_A2::~A() 被调用。m_i = 5
- B.m_A1::~A() 被调用。m_i = 3 4 B::~A() 被调用,m_i = 1
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 的构造与初始化列表顺序无关,而是它们的声明顺序。
回答by Caleb
Output from the modified code is:
修改后的代码输出为:
A() C-tor
A() C-tor
B() C-tor
~B() D-tor
~A() D-tor
~A() D-tor