1
#include<iostream>
using namespace std;

class A
{
public:
        int i;
        A() {cout<<"A()"<<endl;}
        ~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
        int j;
        B(): j(10)
        {
                this->i=20;
                this->~A();
        }
};

int main()
{
        B abc;
        cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main

2つの質問:

  1. オブジェクトを破棄するのではなく、なぜAのデストラクタが通常の関数のように呼び出されるのですか?(または、子クラスのデストラクタが基本クラスのデストラクタを呼び出した場合にのみ基本クラスが破棄されるというのは、ある種のルールですか?)このサンプルコードを試して、デストラクタがどのように機能するかを調べました。したがって、デストラクタ関数を呼び出してもオブジェクトが破棄されない場合は、デストラクタを呼び出す他の種類の呼び出しが明らかに存在し、その場合にのみオブジェクトが破棄されます。そのような電話の何がそんなに特別なのか、そしてそれは何の電話なのか?
  2. BのコンストラクターにAの初期化リストを作成する方法はありますか?このようなもの:

    class B:public A
    { 
        B(): j(10), A():i(20) {}
    };
    
4

7 に答える 7

5
  1. 基本クラスのデストラクタ仮想である必要があります。ここでは、スタック上に作成されているため、問題はありませんが、とにかく..
  2. class A()いいえ。ただし、次のように、Bのコンストラクターの初期化リストでコンストラクターを呼び出すことができます。
    B(): A( .. ), ...

A* a = new B();
//..
delete a;

デストラクタが仮想でない限り、Bのデストラクタを呼び出しませ。そのため、STLコンテナを派生させるべきではありません。それらのデストラクタは仮想ではありません。class A

于 2010-10-26T08:30:03.017 に答える
5
  1. デストラクタは、呼び出すことができる他の通常の関数と同じです(ただし、新しい配置を使用しない限り、絶対に実行しないでください)。オブジェクトを呼び出すdeleteと、2つのことが起こります。デストラクタがクリーンアップのために呼び出され、次にoperator deleteオブジェクトに割り当てられたメモリを解放するために呼び出されます。ここでは、2番目のステップは実行されていません。

  2. いいえ、そのように呼ぶことはできません。あなたができることはこのようなものです:

    クラスA{public:A(int n):i(n){}};

    クラスB:public A {public:B():A(20)、j(10){}};

于 2010-10-26T08:35:06.750 に答える
3

@Nav:いいえ、「破壊された」というあなたの理解は間違っています。オブジェクトのデストラクタが呼び出されると、オブジェクトは破棄されます。あなたはそれが存在していた記憶が完全に蒸発すると信じているようですが、それは決して起こりません。オブジェクトはもう存在しませんが、一部のガベージデータは通常、オブジェクトによって残されます。C++のルールを破り、未定義の動作を呼び出す場合は、残りのバイトを読み取ることができ、次のようになります。オブジェクトであり、有効なオブジェクトにアクセスしているかどうかのランタイムチェックがないため、多くの場合、それらをオブジェクトとして扱うことができます。あなたはどちらをしますか。

それは違法であり、未定義の動作ですが、実際にはしばしば機能します。

繰り返しになりますが、デストラクタはメモリを物理的に気化しません。デストラクタが実行された後も、RAMの容量は同じです。概念的には、デストラクタが実行されると、オブジェクトは存在しなくなります。しかし、そこに含まれるデータはまだメモリにあります。

于 2010-10-26T10:35:39.243 に答える
3

ポイントの場合:

  1. これは未定義の動作ですが、〜A()は仮想として宣言されていないため、クラスBのインスタンスを介して呼び出されるのは〜A()のみです。ウィキペディアで詳細を参照してください。
  2. いいえ。派生クラスの場合、最初に親クラスを呼び出してから、パラメーターを割り当てます。

ウィキペディアのポイント1)について:

仮想デストラクタがない場合、クラスBのインスタンスを削除すると、オブジェクトがBのインスタンスとして削除された場合、BとAの両方のデストラクタが正しく呼び出されますが、基本クラスAへのポインタを介して削除されたBのインスタンスは、未定義の動作を生成します。

例(ポイント2の場合):

B(): A(), j(10) {}

また

B(): A() {j = 10;}
于 2010-10-26T08:56:48.483 に答える
2

1)C ++でのデストラクタの呼び出し順序は、コンストラクタの呼び出し順序と逆の順序です。したがって、最初に派生したクラスオブジェクトはdestroyを取得し、次に基本クラスオブジェクトを取得します。

2)いいえ。

于 2010-10-26T08:35:54.667 に答える
2

あなたが与えているコードでは、実際に基本クラスを破壊していますi。デストラクタを呼び出してからデッド オブジェクトを使用することは、未定義の動作です。動作するか、クラッシュする可能性があります。

iより複雑なものint(a など) である必要がvectorあり、それを使用して何かを実行しようとすると、おそらくクラッシュする可能性があります。

于 2010-10-26T09:50:48.663 に答える
2

~SomeClass() を自分で明示的に呼び出すと、デストラクタ関数が呼び出されます。これにより、オブジェクト (この場合、オブジェクトの基本クラス部分) が破棄された状態になります。

デストラクタは仮想ではないため、派生クラスのデストラクタは呼び出されませんが、SomeClass の基本クラスも破棄されます。

i メンバーだけを使用して A が本当に破棄されているかどうかを調べようとするのは、適切なテストではありません。実際、オブジェクトを使用すると未定義の動作が発生するため、これをテストすることはできません。機能する場合と機能しない場合があります(あなたの場合、おそらく「i = 20 j = 10」と出力されますが、iはすでに破棄されています)。

于 2010-10-26T09:56:22.913 に答える