簡體   English   中英

構造函數和析構函數調用

[英]Constructor and destructor Calls

當我們創建派生類的對象時,為什么以從上到下的方式調用構造函數(首先是基本構造函數,然后是派生構造函數),又是從下到上的析構函數(首先是派生構造函數,然后是基本構造函數) )

為了向新手解釋,請考慮您正在建造新建築物。

您在地下一層,第二層構建地下室。 銷毀時,將銷毀2樓,1樓和地下室。

同樣,對象的構造/銷毀在C ++中發生。

希望這有助於理解。

內存分配獨立於調用構造函數和析構函數。 在構造派生對象時,將為整個類型分配內存。

然后,調用其構造函數(而不是基本構造函數)。 但是,此構造函數首先調用基類的構造函數。 默認情況下,將調用基本的默認構造函數,但是您可以指定如何在派生的構造函數中調用基本構造函數。 如果不存在此類,並且您未指定如何構造基類,則為編譯錯誤。

class Base {
    int x;
public:
    Base() : x(42) {}
};

class Derived : public Base {
    int y;
public:
    Derived() : Base(), y(1337) {}
    // is the same as: Derived() {}
};

在這里, Base()是不可能的(它沒有提供默認的構造函數):

class Base {
    int x;
public:
    Base(int x) : x(x) {}
};

class Derived : public Base {
    int y;
public:
    Derived() : Base(),   y(1337) {}  // <-- error!
    Derived() : Base(42), y(1337) {}  // <-- ok!
};

如您所見,從技術上講,派生構造函數是第一個被調用的構造函數。 但是由於它從一開始就調用了base構造函數,因此實際上是相反的:構造了base,然后派生類“添加”自己的東西。

破壞只是相反的方式:派生類的實例需要清除它添加到基類中的內容,然后才能破壞基類。

可以簡單地將其想象成蓋房子:您必須先建造底座,然后添加故事,最后是屋頂。 破壞時,先移開屋頂,然后移開故事,最后擺脫基礎。

這是另一條規則的結果:所有基本構造函數在進入派生構造函數的主體之前被調用,而所有基本構造函數在離開派生析構函數的主體之后被調用。

考慮以下(過於簡化的)代碼:

class BaseMember
{
public:
    bool Pred();
};

class DerivedMember
{
public:
    void DoFirst(bool);
    void DoLast(bool);
};

class Base
{
public:
    Base() {baseMember=new BaseMember;}
    ~Base(){delete baseMember;}
protected:
    BaseMember *baseMember;
};

class Derived: public Base
{
public:
    Derived()
    {
        derivedMember=new DerivedMember;
        derivedMember->DoFirst(baseMember->Pred());
    }
    ~Derived()
    {
        derivedMember->DoLast(baseMember->Pred());
        delete derivedMember;
    }
protected:
    DerivedMember *derivedMember;
};

我們可以這樣寫,因為在進入Derived構造函數的主體之前,我們依賴於Base的完全構造(所有Base的bases構造函數已完成,所有Base成員構造函數也已完成,Base的構造函數主體已完成)。 這樣,我們可以使用所有基地的成員,知道它們是被構造的。 當我們進入派生的析構函數的主體時,我們知道還沒有破壞任何事物,因此我們可以使用所有基地的成員,知道它們仍然存在,並將在以后被破壞。

構造函數/析構函數調用層次結構是此邏輯的結果。 如果我們在輸入Derived()的主體之前調用Base構造函數,並且Base本身是從BaseOfBase派生的,則Base構造函數將在輸入Base()的主體之前調用BaseOfBase()構造函數。 如果我們在離開〜Derived()析構函數的主體之后調用〜Base()析構函數,則在〜Base()析構函數完成之后,將調用〜BaseOfBase()析構函數。

在C ++中,多重繼承(和虛擬繼承)將進一步使調用層次結構復雜化,但是在這種情況下也適用相同的邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM