10

以下のこの例は、派生クラスがコピーされないようにする方法を示しています。これは、コピーコンストラクタとコピー代入演算子の両方が宣言されている基本クラスに基づいていますprivate

class Uncopyable
{
protected:
   // allow construction and destruction of derived objects...
   Uncopyable() {}
   ~Uncopyable() {}

private:
   // but prevent copying...
   Uncopyable(const Uncopyable&);
   Uncopyable& operator=(const Uncopyable&);
};

このクラスをプライベート継承と組み合わせて使用​​すると、クラスをコピーできなくなります。

class derived: private Uncopyable
{...};

クラスのデストラクタが次のようにUncopyable宣言されていないことに注意してください。virtual.

以前、私はそれを学びました

  • 基本クラスのデストラクタはである必要がありますvirtual
  • 非基本クラスのデストラクタは作成しないでくださいvirtual

この例では、のデストラクタはでUncopyableはありませんvirtualが、から継承されています。これは私が以前に学んだ知恵に反しているようです。

基本クラスのデストラクタを次のように定義しないのはいつ、なぜvirtualですか?

4

5 に答える 5

12

virtual基本クラスのデストラクタは、基本型のポインタを介して派生型のオブジェクトの割り当てを解除しようとする場合にのみ必要です。したがって、の場合のように、パブリックではなくプライベートで基本クラスから継承する場合プライベート継承を使用するとポインタを取得できないため、デストラクタを配置することを心配する必要はありません。派生オブジェクトを作成し、基本型へのポインタに格納します。Uncopyablevirtual

別の例として、このようなミックスインクラスを使用して、クラスにオブジェクト割り当ての数を追跡させる場合があります。この場合、ミックスインは動作を取得するために継承されますが、多態的に処理されることはありません。

template <typename T> class Counter {
public:
    Counter() { ++numInstances; }
    Counter(const Counter&) { ++numInstances );
    ~Counter() { --numInstances; }

    static unsigned getNumInstances() { return numInstances; }

private:
    static unsigned numInstances;
}
template <typename T> unsigned Counter<T>::numInstances = 0;

より一般的には、静的ポリモーフィズムを使用する場合、基本型へのポインターを使用してクラスをポリモーフィックに処理することはないため、仮想デストラクタは必要ありません。派生型へのポインタのみを使用します。

ここで取り上げなかったケースは他にもいくつかありますが、これら2つ(プライベート継承、ミックスインクラス、静的ポリモーフィズム)は、仮想デストラクタが不要なスペースの大部分をカバーしています。

于 2011-08-10T02:04:16.800 に答える
2

ベースをインターフェースとしてではなく、実装の詳細として設計する場合(privateからの継承に注意してくださいUncopyable)。

于 2011-08-10T02:04:23.350 に答える
1

誰もコピー不可*として削除しないことがわかっている場合は、技術的にはデコストラクタを仮想化する必要はありませんが、常に同じサブクラスとして削除します。

はい、これは基本的に@templatetypedefが言ったことですが、おそらくもっと簡単な方法で説明します。

だから:人々がこのようなことをするかもしれないなら:

void aFunction(Uncopyable* obj) {
    delete obj;
}

次に、デストラクタを仮想として宣言する必要があります(潜在的なサブクラスがデストラクタを呼び出すようにするため)。

ただし、次のようにサブクラスを削除することがわかっている場合は、次のようにします。

class Widget : public Uncopyable
{
  ....
};

void aFunction(Widget* obj) {
   delete obj;
}

次に、デストラクタを仮想化する必要はありません(サブクラスのデストラクタが呼び出されるため)。

少なくとも、それは私の理解です。

于 2011-08-10T02:05:33.477 に答える
0

オブジェクトをvtableのないプレーンな古いデータにする必要がある場合。基本クラスのデストラクタで「仮想」を除外する時間の99%は、誰かが修正したいと思う単なる間違いであるため、必要に応じてコメントします。

于 2011-08-10T02:04:01.773 に答える
0

一般的なルールは、デストラクタをパブリックにして仮想にするか、保護して非仮想にすることです。最初のケースでは、オブジェクトは破壊可能なポリモーフィックを使用し、仮想デストラクタは正しいことを行います。2番目のケースでは、実際の子クラスとしてのみ破棄され、それでも正しいことを行います。

于 2011-08-10T02:56:24.553 に答える