`

C++构造函数和析构函数的调用顺序

 
阅读更多
以下是两个测试BaseClass
class BaseClassA
{
public:
    BaseClassA(int a)
    {
        m_nNumberA = a;
        cout << "调用基类A的构造函数!\n";
        OutputDebugString("调用基类A的构造函数!\n");
    }

    ~BaseClassA()
    {
        cout << "调用基类A的析构函数!\n";
        OutputDebugString("调用基类A的析构函数!\n");
    }

private:
    int m_nNumberA;
};

class BaseClassB
{
public:
    BaseClassB(int b)
    {
        m_nNumberB = b;
        cout << "调用基类B的构造函数!\n";
        OutputDebugString("调用基类B的构造函数!\n");
    }

    ~BaseClassB()
    {
        cout << "调用基类B的析构函数!\n";
        OutputDebugString("调用基类B的析构函数!\n");
    }

private:
    int m_nNumberB;
};


测试一:
1 首先优先调用基类的构造函数,而不是自己的构造函数;
2 一般基类的构造函数是采取先到先构造的原则,也就是说根据基类继承的顺序依次调用构造函数;
3 基类构造函数调用完毕后,最后调用子类自己的构造函数;
4 当析构函数调用顺序确定后,析构函数的调用也确定了,完全和构造函数的调用顺序相反;

class DeriveClassA: public BaseClassA, BaseClassB
{
public:
    DeriveClassA(int a, int b)
        : BaseClassA(a)
        , BaseClassB(20)
    {
        m_nTestNumber = b;

        cout << "调用派生类A的构造函数!\n";
        OutputDebugString("调用派生类A的构造函数!\n");
    }

    ~DeriveClassA()
    {
        cout << "调用派生类A的析构函数!\n";
        OutputDebugString("调用派生类A的析构函数!\n");
    }

private:
    int m_nTestNumber;
};

void ConstructorTestA()
{
    DeriveClassA a(100, 200);

    //常规继承详细调用顺序
    //////////////////////////////////////////////////////////////////////////
    //1 首先调用DeriveClassA第一个继承对象BaseClassA的构造函数;
    //2 其次调用DeriveClassA第二个继承对象BaseClassB的构造函数;
    //3 调用DeriveClassA自己的构造函数
    //4 按照构造函数调用的相反顺序依次调用DeriveClassA的析构函数->BaseClassB的析构函数->BaseClassA的析构函数
}

调用基类A的构造函数!
调用基类B的构造函数!
调用派生类A的构造函数!
调用派生类A的析构函数!
调用基类B的析构函数!
调用基类A的析构函数!





测试二:
1 首先优先调用基类的构造函数,而不是自己的构造函数;
2 一般基类的构造函数是采取先到先构造的原则,也就是说根据基类继承的顺序依次调用构造函数;
3 基类构造函数调用完毕后,开始调用类变量(成员)的构造函数,构造函数和类的初始化列表相关,也就是说,这时候的成员初始化顺序决定了这部分类变量(成员)的构造函数调用次序;
4 基类构造函数和类变量(成员)的构造函数调用完毕后,最后调用子类自己的构造函数;
5 当析构函数调用顺序确定后,析构函数的调用也确定了,完全和构造函数的调用顺序相反;

class DeriveClassB: public BaseClassA, public BaseClassB
{
public:
    DeriveClassB(int a, int b)
        : BaseClassB(20) //这个两个故意调整顺序来确定基类构造函数和这个排版顺序无关
        , BaseClassA(a)  //
        , m_BaseClassB(a+b)
        , m_BaseClassA(200)
    {
        m_nTestNumber = b;

        cout << "调用派生类B的构造函数!\n";
        OutputDebugString("调用派生类B的构造函数!\n");
    }

    ~DeriveClassB()
    {
        cout << "调用派生类B的析构函数!\n";
        OutputDebugString("调用派生类B的析构函数!\n");
    }

private:
    int m_nTestNumber;
    BaseClassB m_BaseClassB;
    BaseClassA m_BaseClassA;
};

void ConstructorTestB()
{
    DeriveClassB b(100, 200);
    //带有对象成员的继承调用顺序
    //////////////////////////////////////////////////////////////////////////
    //1 首先调用DeriveClassA第一个继承对象BaseClassA的构造函数,这个和继承顺序有关,和构造函数初始化列表无关;
    //2 其次调用DeriveClassA第二个继承对象BaseClassB的构造函数;
    //3 调用DeriveClassA中成员对象m_BaseClassB的构造函数,这个顺序和构造函数初始化成员列表有关;
    //4 调用DeriveClassA中成员对象m_BaseClassA的构造函数;
    //5 调用DeriveClassA自己的构造函数
    //6 按照构造函数调用的相反顺序依次调用DeriveClassA的析构函数->BaseClassA的析构函数->BaseClassB的析构函数->BaseClassB的析构函数->BaseClassA的析构函数(这个应该是堆栈有关)

}

调用基类A的构造函数!
调用基类B的构造函数!
调用基类B的构造函数!
调用基类A的构造函数!
调用派生类B的构造函数!
调用派生类B的析构函数!
调用基类A的析构函数!
调用基类B的析构函数!
调用基类B的析构函数!
调用基类A的析构函数!






测试三:(首先这个测试是在测试一的基础上修改而来,和测试一对比可以了解虚继承类的构造调用)
1 首先优先调用基类的构造函数,而不是自己的构造函数;
2 如果有虚继承,应该首先确定虚基类的列表,依次优先调用虚基类的构造函数;最后再把一般的继承函数按照顺序依次调用构造函数;
3 基类构造函数调用完毕后,最后调用子类自己的构造函数;
4 当析构函数调用顺序确定后,析构函数的调用也确定了,完全和构造函数的调用顺序相反
class DeriveClassC: public BaseClassA, virtual public BaseClassB
{
public:
    DeriveClassC(int a, int b)
        : BaseClassA(a)
        , BaseClassB(20)
    {
        m_nTestNumber = b;

        cout << "调用派生类C的构造函数!\n";
        OutputDebugString("调用派生类C的构造函数!\n");
    }

    ~DeriveClassC()
    {
        cout << "调用派生类C的析构函数!\n";
        OutputDebugString("调用派生类C的析构函数!\n");
    }

private:
    int m_nTestNumber;
};

void ConstructorTestC()
{
    DeriveClassC a(100, 200);

    //虚继承详细调用顺序
    //重点:在多重继承中,优先考虑虚继承的类,对它优先初始化
    //////////////////////////////////////////////////////////////////////////
    //1 首先调用DeriveClassA第一个继承对象BaseClassB的构造函数;虽然BaseClassA继承排在BaseClassB的前面,但是BaseClassB是虚继承,所以优先构造;
    //2 其次调用DeriveClassA第二个继承对象BaseClassA的构造函数;
    //3 调用DeriveClassA自己的构造函数
    //4 按照构造函数调用的相反顺序依次调用DeriveClassA的析构函数->BaseClassA的析构函数->BaseClassB的析构函数
}

调用基类B的构造函数!
调用基类A的构造函数!
调用派生类C的构造函数!
调用派生类C的析构函数!
调用基类A的析构函数!
调用基类B的析构函数!




void ConstructorTest()
{
    ConstructorTestA();
    ConstructorTestB();
    ConstructorTestC();
}

分享到:
评论

相关推荐

    包含构造函数和析构函数的C++程序

    ### 构造函数和析构函数在C++中的应用 #### 概述 构造函数与析构函数是C++编程语言中非常重要的概念,它们在类的实例化和销毁过程中扮演着关键角色。通过理解这些函数的工作原理及其作用,我们可以更好地控制对象...

    C++构造函数和析构函数的调用顺序1

    在C++编程中,构造函数和析构函数是类的...这个例子展示了构造函数和析构函数调用的直观顺序,帮助理解C++对象生命周期管理的基本原理。在实际编程中,理解和掌握这一点对于防止内存泄漏和资源未释放等问题至关重要。

    构造函数和析构函数PPT课件.pptx

    构造函数和析构函数PPT课件.pptx ...构造函数和析构函数是C++编程语言中两个非常重要的概念,它们在对象的创建和销毁过程中扮演着关键的角色。了解构造函数和析构函数的概念和用法是编写高效的C++程序的关键。

    C++构造函数和析构函数顺序

    在C++编程中,构造函数和...总之,理解C++中构造函数和析构函数的调用顺序以及何时使用虚析构函数是编写健壮和可维护的代码的关键。遵循这些规则,可以确保对象正确初始化并释放资源,避免潜在的内存问题和异常行为。

    c++构造函数和析构函数,拷贝,重载

    根据给定的文件标题“C++构造函数和析构函数,拷贝,重载”以及描述“一道很好的习题代码,包含构造、析构、拷贝、重载”,我们可以了解到这段代码主要涉及到了C++中类的设计与实现,特别是构造函数、析构函数、拷贝...

    C++中构造函数与析构函数的调用顺序详解

    以下是关于C++构造函数与析构函数调用顺序的详细解释。 首先,构造函数的调用顺序遵循以下原则: 1. **基类构造函数**:当创建一个对象时,首先调用的是最远基类的构造函数,然后逐级向上,直到到达最接近的基类。...

    C++构造函数,复制构造函数和析构函数专题[1].pdf

    在C++编程语言中,构造函数、复制构造函数和析构函数是面向对象特性的重要组成部分,它们在对象的生命周期管理中扮演着至关重要的角色。同时,继承、虚函数和多态性是C++实现面向对象设计的核心概念。下面将详细讨论...

    深入解析C++中的构造函数和析构函数

    调用构造函数和析构函数的顺序:先构造的后析构,后构造的先折构。它相当于一个栈,先进后出。 代码如下:#include&lt;iostream&gt;#include&lt;string&gt;using namespace std;class Student{ public: Student(string,string,...

    析构或构造函数声明为保护或私有成员

    将构造函数和析构函数声明为保护成员,可以限制外部用户直接调用这些函数,但允许子类的成员函数调用。例如: ```cpp class A { protected: A() {} public: // ... }; class B : public A { public: B() {} //...

    构造函数和析构函数程序(c++)

    构造函数的调用可以追踪。。。。由于构造函数和析构函数都是自动吊桶的或者更不饿,我们可以自己设立函数来追踪构造函数的调用过称。

    构造函数和析构函数的详细解释

    构造函数和析构函数是C++中面向对象编程的关键概念,它们在类对象的生命周期中起着至关重要的作用。 构造函数是一种特殊类型的成员函数,它在创建类的对象时被自动调用。其主要任务是初始化对象的状态,为数据成员...

    C++构造和析构的多态

    ### C++构造和析构中的多态实现 在C++编程语言中,多态是一种重要的特性,它允许程序员编写能够处理不同数据类型的代码。多态的实现通常依赖于虚函数和虚函数表(vtable)。然而,在构造函数和析构函数中调用虚函数...

    章构造函数和析构函数PPT学习教案.pptx

    在C++编程语言中,构造函数和析构函数是面向对象程序设计的重要组成部分,它们主要用于对象的初始化和清理工作。本教程将详细讲解这两个概念及其应用。 首先,构造函数是类的一个特殊成员函数,它的主要任务是在...

    工学四川大学C构造函数和析构函数PPT学习教案.pptx

    在C++编程语言中,构造函数和析构函数是类的两种特殊成员函数,它们在对象的生命周期中扮演着至关重要的角色。本章主要讲解了关于C++中构造函数和析构函数的基本概念、用途以及相关特性。 首先,构造函数...

    c++程序设计第十章构造函数和析构函数

    在C++程序设计中,构造函数和析构函数是类的重要组成部分,它们分别在对象创建和销毁时自动调用,负责对象的初始化和清理工作。 ### 构造函数 构造函数是一种特殊类型的成员函数,其名称必须与类名完全一致,并且...

    构造函数和析构函数PPT学习教案.pptx

    【构造函数和析构函数】是面向对象编程中的核心概念,主要应用于C++语言中。它们在类的设计和对象的生命周期管理中起着至关重要的作用。 **构造函数**是类的一种特殊成员函数,用于在创建对象时进行初始化操作。它...

    C++构造函数和析构函数的使用与讲解

    "C++构造函数和析构函数的使用与讲解" C++语言中,构造函数和析构函数是两个非常重要的概念,它们都是类成员函数,分别用于对象的创建和销毁。本文将详细讲解构造函数和析构函数的使用和实现。 1. 构造函数 构造...

    构造函数和析构函数习题.pdf

    "构造函数和析构函数习题" 构造函数是C++编程语言中的一种特殊函数,它们在对象创建时自动执行,以便对对象进行初始化。析构函数是与构造函数相对应的,用于释放对象所占用的资源。在本文中,我们将详细讨论构造...

Global site tag (gtag.js) - Google Analytics