继承中调用构造函数/析构函数的顺序

关于创建对象的一个小问题。说我有这两个类:


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;

};

并在主要我创建一个实例B:


int main(){

    B b;

}

请注意,B派生自A并且还具有类型的字段A。


我想弄明白这些规则。我知道构造一个对象时首先调用它的父构造函数,反之亦然。


字段怎么样(A a;在这种情况下)?什么时候B创建,什么时候会调用它A的构造函数?我还没有定义初始化列表,是否有某种默认列表?如果没有默认列表?关于破坏的同样问题。


慕桂英4014372
浏览 398回答 3
3回答

qq_花开花谢_0

施工总是从基地开始class。如果有多个基础,class那么构造从最左边的基础开始。(旁注:如果有virtual继承,则给予更高的偏好)。然后构造成员字段。它们按声明的顺序初始化最后,它class本身就构建了析构函数的顺序正好相反无论初始化列表如何,呼叫顺序都是这样的:Base&nbsp;class A的构造函数class B将构造名为a(类型class A)的字段派生class B的构造函数

宝慕林4294392

假设没有虚拟/多重继承(这使事情变得复杂很多),那么规则很简单:分配对象存储器执行基类的构造函数,以大多数派生结束执行成员初始化该对象成为其类的真实实例执行构造函数代码需要记住的一件重要事情是,直到第4步,对象还不是其类的实例,因为它只有在构造函数的执行开始后才能获得此标题。这意味着如果在成员的构造函数期间抛出异常,则不会执行对象的析构函数,但只会破坏已构造的部分(例如成员或基类)。这也意味着如果在成员或基类的构造函数中调用对象的任何虚拟成员函数,则调用的实现将是基础实现,而不是派生实现。另一个要记住的重要事项是,初始化列表中列出的成员将按照它们在类中声明的顺序构建,还要注意,即使在执行构造函数代码期间,this对象已经获得了它的最终类(例如,关于虚拟分派),除非构造函数完成其执行,否则不会调用类的析构函数。只有当构造函数完成执行时,对象实例才是实例中真正的第一类公民...在此之前只是一个“想成为实例”(尽管有正确的类)。破坏以完全相反的顺序发生:首先执行对象析构函数,然后它丢失其类(即从对象上的这一点被视为基础对象)然后所有成员以反向声明顺序销毁,最后是基类销毁过程被执行到最抽象的父级。对于构造函数,如果在基类或成员析构函数中调用对象的任何虚拟成员函数(直接或间接),则执行的实现将是父实例,因为在类析构函数完成时对象丢失了其类标题。

摇曳的蔷薇

基类始终在数据成员之前构建。数据成员按照在类中声明的顺序构造。此顺序与初始化列表无关。初始化数据成员时,它将查看参数的初始化列表,如果没有匹配则调用默认构造函数。始终以相反的顺序调用数据成员的析构函数。
打开App,查看更多内容
随时随地看视频慕课网APP