24-3 派生类的构造顺序

在上节关于24.2 节 C++基本继承的课程中,你了解到类可以从其他类继承成员和函数。本节我们将深入探讨派生类实例化时构造函数的执行顺序。

首先,让我们引入几个新类来阐明关键概念。

class Base
{
public:
    int m_id {};

    Base(int id=0)
        : m_id { id }
    {
    }

    int getId() const { return m_id; }
};

class Derived: public Base
{
public:
    double m_cost {};

    Derived(double cost=0.0)
        : m_cost { cost }
    {
    }

    double getCost() const { return m_cost; }
};

在此示例中,派生类 Derived 继承自基类 Base。

image

由于派生类继承了基类的函数和变量,你可能会认为基类的成员被复制到了派生类中。但事实并非如此。相反,我们可以将派生类视为由两部分组成的类:一部分是派生类本身,另一部分则是基类。

image

你已经看到许多实例,展示了当我们实例化一个普通(非派生)类时会发生什么:

int main()
{
    Base base;

    return 0;
}

基类是一个非派生类,因为它不继承自任何其他类。C++ 为基类分配内存后,会调用基类的默认构造函数进行初始化。

现在让我们看看实例化派生类时会发生什么:

int main()
{
    Derived derived;

    return 0;
}

如果你亲自尝试这个操作,你不会发现它与之前实例化非派生类 Base 的示例有何不同。但在幕后,事情的发生方式略有不同。如前所述,派生类本质上由两部分构成:基类部分和派生类部分。C++构造派生对象时采用分阶段方式:首先构造继承树顶端的基类,随后按顺序构造每个子类,直至最后构造继承树底端的派生类。

因此当实例化派生类时,首先构造其基类部分(使用基类的默认构造函数)。基类部分完成后,再构造派生类部分(使用派生类的默认构造函数)。此时已无更多派生类,构造过程即告完成。

这个过程其实很容易用图示说明。

#include <iostream>

class Base
{
public:
    int m_id {};

    Base(int id=0)
        : m_id { id }
    {
        std::cout << "Base\n";
    }

    int getId() const { return m_id; }
};

class Derived: public Base
{
public:
    double m_cost {};

    Derived(double cost=0.0)
        : m_cost { cost }
    {
        std::cout << "Derived\n";
    }

    double getCost() const { return m_cost; }
};

int main()
{
    std::cout << "Instantiating Base\n";
    Base base;

    std::cout << "Instantiating Derived\n";
    Derived derived;

    return 0;
}

该程序产生以下结果:

image

如你所见,在构造派生类时,其基类部分会优先完成构造。这符合逻辑:子类无法脱离父类而存在。这种做法也更安全:子类常需调用父类的变量和函数,而父类对子类一无所知。先实例化父类可确保派生类创建时,父类的变量已完成初始化并可供使用。


继承链的构造顺序

有时类会从其他类派生,而这些类本身又从其他类派生。例如:

#include <iostream>

class A
{
public:
    A()
    {
        std::cout << "A\n";
    }
};

class B: public A
{
public:
    B()
    {
        std::cout << "B\n";
    }
};

class C: public B
{
public:
    C()
    {
        std::cout << "C\n";
    }
};

class D: public C
{
public:
    D()
    {
        std::cout << "D\n";
    }
};

请记住,C++ 总是先构造“最顶层”或“最基础”的类。随后它会按顺序遍历继承树,依次构造每个派生类。

以下是一个简短程序,演示了沿继承链创建的顺序。

int main()
{
    std::cout << "Constructing A: \n";
    A a;

    std::cout << "Constructing B: \n";
    B b;

    std::cout << "Constructing C: \n";
    C c;

    std::cout << "Constructing D: \n";
    D d;
}

此代码输出以下内容:

image


结论

C++分阶段构造派生类,从最基类(位于继承树顶端)开始,直至最子类(位于继承树底端)。每个类构造时,都会调用该类对应的构造函数来初始化该部分。

请注意,本节示例类均采用了基类的默认构造函数(为简化起见)。在下一课中,我们将深入探讨构造函数在派生类构造过程中的作用(包括如何明确指定派生类应使用的基类构造函数)。

posted @ 2026-01-31 19:41  游翔  阅读(1)  评论(0)    收藏  举报