1

元:

class base
{
public:
  base()
  {
    // allocate memory for basearray
  }
  virtual ~base()
  {
    // delete basearray
  }

protected:
  float* basearray;
};

class derived1 : public base
{
public:
  derived1()
  {
    // allocate memory for derivedarray
  }
  ~derived1()
  {
    // delete derived array
  }

protect:
  float* derivedarray;
};

void main()
{
  derived1 d;

  ...

  base* pb = &d;

  ...

  // Delete base array? 
}

基本クラスに仮想デストラクタと配列があります。基本クラスのデストラクタが派生クラスのデストラクタによってオーバーライドされた場合、basearray は削除されません。素敵な解決策は何ですか?

4

5 に答える 5

9

基本クラスのデストラクタ、派生クラスのデストラクタが実行された直後に自動的に呼び出されます。

于 2012-01-30T19:31:42.777 に答える
2

派生オブジェクトを破棄し、ベースのデストラクタが仮想の場合、両方のデストラクタが呼び出されます。これはこちらで確認できます: http://ideone.com/RZamr

順序はコンストラクターの順序と逆になります。つまり、最初にコンストラクターを構築するときに、のコンストラクターbaseが呼び出され、次にof が呼び出されderivedます。最初に破壊する場合、 のデストラクタderivedが呼び出され、次に のデストラクタが呼び出されbaseます。

于 2012-01-30T19:34:56.450 に答える
1

仮想デストラクタは、基本クラスの仮想デストラクタがオーバーライドされないという点で、他の仮想関数と同じようには機能しません。代わりに、サブクラスが独自のデストラクタを提供すると、そのサブクラスのデストラクタが起動し、次に基本クラスのデストラクタも起動します。ここで「仮想」が使用されているのは、基本クラス ポインターを介して派生クラス オブジェクトを削除する場合、C++ が、ポインターの静的型 (サブクラス) ではなく、オブジェクトの動的型 (サブクラス) に基づいてデストラクタを呼び出すことを認識するためです。スーパークラス)。したがって、ここで特別なことをする必要はありません。基本クラスのデストラクタは通常どおり機能します。

お役に立てれば!

于 2012-01-30T19:35:28.293 に答える
0

デストラクタをオーバーライドするとき、基本クラスのデストラクタは、それが「仮想」として定義されている限り呼び出されます。これはあなたが行ったことです。

したがって、この例では:

  class base
  {
  public:
     base()
     {
        myarray = new float[100];
     }

     ~base()
     {
        delete[] myarray;
     }

  private:
     float* myarray;
  }


  class derived : public base
  {
  public:
     derived()
     {
     }

     ~derived()
     {
     }
  }

基本クラスのデストラクタが派生クラスのデストラクタによって隠されているため、これは 'myarray' を削除せず、メモリ リークを引き起こします。でも:

  class base
  {
  public:
     base()
     {
        myarray = new float[100];
     }

     virtual ~base()
     {
        delete[] myarray;
     }

  private:
     float* myarray;
  }


  class derived : public base
  {
  public:
     derived()
     {
     }

     ~derived()
     {
     }
  }

これにより、アレイが削除されます。

コンストラクターは基本クラスから呼び出されるため、基本クラスのコンストラクターが最初に呼び出され、次に派生クラスが呼び出されますが、デストラクタは逆の順序で呼び出されるため、派生クラスのデストラクタは基本クラスの前に呼び出されます。 .

于 2012-01-30T19:40:24.047 に答える
0

ここは問題ありません。基本クラスのデストラクタは、派生クラスのデストラクタが呼び出された直後に呼び出されます。

これが当てはまらない状況が 1 つだけあります。基本クラスのデストラクタが仮想でない基本クラスへのポインタに対して delete が呼び出された場合です。

スタック上に作成されたクラスのローカル インスタンスがあり、例外が原因であっても関数またはメソッドが終了するすべての状況で、インスタンスは正しく破棄されます。

newクラスのインスタンスが削除され、その後、インスタンス化された正確なクラスへのポインターを介して削除されるすべての状況で、インスタンスは正しく破棄されます。

クラスのインスタンスがnewd であるが、基底クラス ポインターを介して削除された場合、基底クラスに仮想デストラクタがある (virtualそれ自体が宣言されているか、独自のベースに仮想デストラクタがある) 場合にのみ、インスタンスが正しく破棄されます。インスタンスは正しく破棄されます。 .

于 2012-01-30T20:09:57.913 に答える