web-dev-qa-db-ja.com

C ++でデストラクタとコンストラクタが呼び出される順序は何ですか

C++でデストラクタとコンストラクタが呼び出される順序は何ですか?いくつかの基本クラスと派生クラスの例を使用する

46
hozefam

順序は:

  1. 基本コンストラクタ
  2. 派生コンストラクタ
  3. 派生したデストラクタ
  4. ベースデストラクタ

例:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

例の出力:

構成B

構築D

破壊D

破壊B

複数レベルの継承はスタックのように機能します:

アイテムを構築としてスタックにプッシュし、それを破棄として削除することを検討する場合は、スタックのような継承の複数のレベルを見ることができます。

これは任意の数のレベルで機能します。

例D2はDから派生しており、Bから派生しています。

スタックにBをプッシュし、スタックにDをプッシュし、スタックにD2をプッシュします。したがって、構築順序はB、D、D2です。次に、破壊命令を見つけるために飛び出し始めます。 D2、D、B

より複雑な例:

より複雑な例については、@ JaredParによって提供されるリンクを参照してください

60
Brian R. Bondy

仮想継承や多重継承など、これらのイベントの詳細な説明は、C++で入手できますFAQ Lite。セクション25.14および25.15

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

21
JaredPar

また、配列要素は最初に作成される->最後に、逆の順序で破壊されることに注意してください:最後->最初。

10
Ferruccio

誰もがそれを無視しているように見えるので、私は以前の答えに加えなければなりません

derivedクラスインスタンスがcreatedである場合、コードinsidebaseのコンストラクタはbeforeコードinsidederived、ただしderivedは技術的にまだ "created"beforeであることを覚えておいてくださいベース

そして、derivedクラスデストラクタが呼び出されている場合、コードinside派生したデストラクタはbefore前に呼び出されますinsideベースデストラクタですが、basedestroyedbeforederived.

created/destroyedと言っているとき、私は実際にはallocated/deallocatedを参照しています。

これらのインスタンスのメモリレイアウトを見ると、派生インスタンスがベースインスタンスを構成していることがわかります。例えば:

派生メモリ:0x00001110〜0x00001120

ベースのメモリ:0x00001114〜0x00001118

したがって、派生クラスは、構造のベース[〜#〜] [〜#〜]の前に割り当てる必要があります。そして、派生クラスは破壊のベースの割り当て解除[〜#〜] [〜#〜]の後でなければなりません。

次のコードがある場合:

class Base 
{
public:
    Base()
    {
        std::cout << "\n  Base created";
    }
    virtual ~Base()
    {
        std::cout << "\n  Base destroyed";
    }
}

class Derived : public Base 
{
public:
    Derived()
    // Derived is allocated here 
    // then Base constructor is called to allocate base and prepare it
    {
        std::cout << "\n  Derived created";
    }
    ~Derived()
    {
        std::cout << "\n  Derived destroyed";
    }   
    // Base destructor is called here
    // then Derived is deallocated
}

だからあなたが作成した場合Derived d;そしてそれを範囲外にすると、@ Brianの答えで出力が得られます。しかし、メモリ内のオブジェクトの動作は実際には同じ順序ではなく、次のようになります。

建設:

  1. 割り当てられた派生

  2. ベース割り当て

  3. 呼び出された基本コンストラクタ

  4. 呼び出された派生コンストラクタ

破壊:

  1. 派生したデストラクタが呼び出されました

  2. ベースデストラクタが呼び出されました

  3. ベースの割り当て解除

  4. 派生した割り当て解除

5
Everyone