2
using namespace std;

class C
{
    int a;
    public:
        C(int aa=0) {a=aa;}
        ~C() {cout << "Destructor C!" << a << endl;}
};

class D: public C
{
    int b;
    public:
        D(int aa=0, int bb=0): C(aa) {b=bb;}
        ~D() {cout << "Destructor D!" << b << endl;}
};

void test()
{
    D x(5);
    D y(6,7);
}

int main()
{
    test();
}

上はコードで、下は実行結果です。

Destructor D!7
Destructor C!6
Destructor D!0
Destructor C!5

なぜ「デストラクタC!」なのかわかりません。呼び出されます。そして、関連するデストラクタの呼び出しシーケンス。スタックプッシュ/ポップのように感じます。

さらに:なぜ以前に「 Dx(5); 」 と呼ばれるのに、対応する結果が後で示されるのですか?

4

8 に答える 8

3

デストラクタの呼び出しシーケンスは、スタックをポップするように、常に派生からベースに移動します。これにより、派生クラスは基本クラスによって割り当てられたリソースをクリーンアップできます。xこの場合、コンパイラはオブジェクトの正確なタイプをy静的に知っているため、このシーケンスを構築する方法を知っています。

ただし、このシーケンスが壊れてしまう場合があります。コードの次の変更を検討してください。

void test()
{
    C *x = new D(5);
    D *y = new D(6,7);
    delete x;
    delete y;
}

次の出力が生成されます。

Destructor C!5
Destructor D!7
Destructor C!6

これを実行しても、の呼び出しは発生しませ~Dx。の場合y、両方のデストラクタが呼び出されます。

virtualこれは、基本クラスでデストラクタを宣言しなかったためです。デストラクタが仮想でない場合、コンパイラは、オブジェクトが基本クラスへのポインタによって参照される状況で、派生クラスのデストラクタを呼び出さなければならないことを認識していません。このため、継承する必要のあるクラスでは常にデストラクタを仮想化し、リソースを動的に割り当てる必要があります。

于 2012-12-21T11:16:14.170 に答える
3

派生クラスのコンストラクタとデストラクタの呼び出しシーケンスは次のとおりです。

Base  Class  Constructor
Derived  Class  Constructor
Derived  Class  Destructor
Base  Class  Destructor

派生クラスは基本クラスの上に構築されるため、次のようになります。

  • 基本クラスは、派生クラスの前に構築する必要があります。
  • 派生クラスは、基本クラスの前に破棄する必要があります。
于 2012-12-21T11:09:00.620 に答える
2
 I feel that it seems like the stack push/pop.

Cから派生したクラスD。Dコンストラクターを呼び出すと、Cコンストラクターが最初に呼び出され、デストラクタは逆の方法で呼び出されます。

Further: Why it calls "D x(5);" earlier but the corresponding result is given later?

自動オブジェクト(一般に「ローカル変数」と呼ばれる)は、制御フローが定義の範囲を離れると、定義の逆の順序で破棄されます。

于 2012-12-21T11:14:42.767 に答える
1

オブジェクトがクリーンアップされると、最初に派生クラスのデストラクタが呼び出され、次に基本クラスのデストラクタが呼び出されます。

于 2012-12-21T10:59:20.350 に答える
1

インスタンスを作成するDと、のコンストラクターCが呼び出されます。これは、インスタンスからD継承するためです。 再度
破棄すると、デストラクタが呼び出され、次にデストラクタが呼び出されます。DDC

于 2012-12-21T10:59:31.017 に答える
1

継承するときは、継承元のオブジェクトを「拡張」します。したがって、ビルドする場合はD、が必要Cです。そして、あなたが破壊する必要があるとき、あなたはそれを拡張することができるようにあなたが構築するD破壊するでしょう。C

于 2012-12-21T11:02:57.157 に答える
0

C派生クラスのオブジェクトの破棄には、その基本クラスのサブオブジェクトの破棄が含まれるため、のデストラクタが呼び出されます。[class.dtor]パラ8によると:

デストラクタの本体を実行した後...クラスXのデストラクタは呼び出します...Xの直接基本クラスのデストラクタ...

制御フローがスコープを出ると(関数のtest()終了など)、ローカルオブジェクトはLIFO方式で破棄されます。最初に作成されたオブジェクトは最後に破棄されます。[stmt.jump]パラ2によると:

スコープを終了すると(ただし、達成された場合)、そのスコープで作成された自動保存期間(3.7.3)のオブジェクトは、作成と逆の順序で破棄されます。

于 2012-12-21T11:13:42.453 に答える
0

さらに:なぜ「Dx(5);」と呼ばれるのか 以前ですが、対応する結果は後で与えられますか?

これらのオブジェクトはスタックに割り当てられます(ヒープD * d1 = new D();に割り当てられます)。

出力を提供するのは呼び出しではなく、インスタンスがスコープから外れたとき、この場合は終了したときに発生D x(5)するデストラクタへの呼び出しです。~Dmain()

スタックメモリであるため、割り当て解除は割り当てとは逆の順序で行われます。

于 2012-12-21T11:32:44.237 に答える