168

仮想デストラクタの必要性を理解しています。しかし、なぜ純粋な仮想デストラクタが必要なのですか?C ++の記事の1つで、クラスを抽象化する場合は、純粋な仮想デストラクタを使用すると著者は述べています。

ただし、メンバー関数のいずれかを純粋な仮想として作成することにより、クラスを抽象化できます。

だから私の質問は

  1. デストラクタを本当に仮想にするのはいつですか?誰かが良いリアルタイムの例をあげることができますか?

  2. 抽象クラスを作成するとき、デストラクタも純粋な仮想にするのは良い習慣ですか?はいの場合..それではなぜですか?

4

11 に答える 11

128
  1. おそらく、純粋な仮想デストラクタが許可される本当の理由は、それらを禁止することは言語に別のルールを追加することを意味し、純粋な仮想デストラクタを許可することによる悪影響はないため、このルールは必要ないということです。

  2. いいえ、昔ながらの仮想で十分です。

仮想メソッドのデフォルトの実装でオブジェクトを作成し、特定のメソッドをオーバーライドすることを強制せずにオブジェクトを抽象化したい場合は、デストラクタを純粋仮想にすることができます。あまり意味がありませんが、可能です。

コンパイラは派生クラスの暗黙的なデストラクタを生成するため、クラスの作成者が生成しない場合、派生クラスは抽象化されないことに注意してください。したがって、基本クラスに純粋な仮想デストラクタが含まれていても、派生クラスに違いはありません。基本クラスを抽象化するだけです(@kappaのコメントに感謝します)。

また、すべての派生クラスには特定のクリーンアップコードが必要であり、純粋な仮想デストラクタを作成のリマインダーとして使用する必要があると想定することもできますが、これは不自然な(そして強制されていない)ようです。

注:デストラクタは、純粋仮想であっても、派生クラスをインスタンス化するために実装が必要な唯一のメソッドですはい純粋仮想関数は実装を持つことができます)。

struct foo {
    virtual void bar() = 0;
};

void foo::bar() { /* default implementation */ }

class foof : public foo {
    void bar() { foo::bar(); } // have to explicitly call default implementation.
};
于 2009-08-02T19:30:39.327 に答える
33

抽象クラスに必要なのは、少なくとも 1 つの純粋仮想関数だけです。どの機能でもかまいません。しかし、たまたま、デストラクタはどのクラスにもあるものなので、常に候補として存在します。さらに、デストラクタを純粋な仮想 (単なる仮想ではなく) にすると、クラスが抽象化される以外に動作上の副作用はありません。そのため、多くのスタイル ガイドでは、クラスが抽象であることを示すために純粋仮想デスタクタを一貫して使用することを推奨しています。これは、コードを読んでいる人がクラスが抽象かどうかを確認できる一貫した場所を提供する以外の理由がない場合に限ります。

于 2009-08-02T22:03:20.083 に答える
21

抽象基本クラスを作成する場合:

  • インスタンス化することはできません(そうです、これは「抽象」という用語で冗長です!)
  • ただし、仮想デストラクタの動作が必要です (派生型へのポインターではなく、ABC へのポインターを保持し、それらを介して削除する予定です)
  • ただし、他のメソッドには他の仮想ディスパッチ動作は必要ありません(おそらく他のメソッドありませんか? コンストラクタ/デストラクタ/代入を必要とする単純な保護された「リソース」コンテナを検討してください)。

...デストラクタを純粋仮想化し、その定義 (メソッド本体) を提供することで、クラスを抽象化するのが最も簡単です。

仮定の ABC の場合:

インスタンス化できないことを保証し(クラス自体の内部であっても、これがプライベートコンストラクターでは不十分な場合があるためです)、デストラクタに必要な仮想動作を取得し、別のメソッドを見つけてタグ付けする必要はありません。 「仮想」としての仮想ディスパッチは必要ありません。

于 2009-08-02T20:14:25.243 に答える
8

あなたの質問に対する回答から、純粋な仮想デストラクタを実際に使用する正当な理由を推測できませんでした。たとえば、次の理由はまったく納得できません。

おそらく、純粋な仮想デストラクタが許可されている本当の理由は、それらを禁止すると、言語に別のルールを追加することを意味し、純粋な仮想デストラクタを許可しても悪影響が発生しないため、このルールは必要ないからです。

私の意見では、純粋な仮想デストラクタは便利です。たとえば、コードに myClassA と myClassB の 2 つのクラスがあり、myClassB が myClassA を継承しているとします。Scott Meyers が著書「より効果的な C++」の項目 33「非リーフ クラスを抽象化する」で言及した理由により、myClassA と myClassB の継承元となる抽象クラス myAbstractClass を実際に作成することをお勧めします。これにより、抽象化が向上し、オブジェクトのコピーなどで発生する問題が回避されます。

(クラス myAbstractClass を作成する) 抽象化プロセスでは、myClassA または myClassB のメソッドが、純粋な仮想メソッドになるための適切な候補ではない可能性があります (これは、myAbstractClass が抽象化されるための前提条件です)。この場合、抽象クラスのデストラクタ純粋仮想を定義します。

以下は、私が自分で書いたコードの具体的な例です。共通のプロパティを共有する Numerics/PhysicsParams という 2 つのクラスがあります。したがって、抽象クラス IParams から継承させます。この場合、純粋に仮想的な方法を手元にまったく持っていませんでした。たとえば、setParameter メソッドは、すべてのサブクラスに対して同じ本体を持つ必要があります。私が持っていた唯一の選択肢は、IParams のデストラクタを純粋な仮想にすることでした。

struct IParams
{
    IParams(const ModelConfiguration& aModelConf);
    virtual ~IParams() = 0;

    void setParameter(const N_Configuration::Parameter& aParam);

    std::map<std::string, std::string> m_Parameters;
};

struct NumericsParams : IParams
{
    NumericsParams(const ModelConfiguration& aNumericsConf);
    virtual ~NumericsParams();

    double dt() const;
    double ti() const;
    double tf() const;
};

struct PhysicsParams : IParams
{
    PhysicsParams(const N_Configuration::ModelConfiguration& aPhysicsConf);
    virtual ~PhysicsParams();

    double g()     const; 
    double rho_i() const; 
    double rho_w() const; 
};
于 2015-01-11T14:56:28.780 に答える
5

実装済みでテスト済みの派生クラスを変更せずに基本クラスのインスタンス化を停止する場合は、基本クラスに純粋な仮想デストラクタを実装します。

于 2011-04-21T09:20:20.247 に答える
-2

デストラクタを仮想化しない場合、コンパイラは基本クラスの内容のみを破壊し、すべての派生クラスは変更されず、コンパイラは他のデストラクタを呼び出さないため、デストラクタを仮想化する必要があります。基本クラスを除くクラス。

于 2013-09-09T18:09:30.460 に答える