0

プロジェクトでは、次の問題があります。

私は非常に単純な継承スキームを持っています(構成ではなく継承が必要です):

クラスベース

-> クラス DerivedA

-> クラス DerivedB

-> クラス DerivedC

A、B、C は Base から派生し、それだけです。だから今私は2つの選択肢があります:

仮想性を伴う公開継承

仮想性のない私的継承

いくつかの最適化の理由から (大量のインライン化が必要です)、仮想性は必要ありません...そしてプライベート継承も必要ありません。残っている唯一のオプションはCRTPだと思います。しかし、基本クラスには約 300 の関数があり、そこに CRTP を実装するのは本当に面倒です。

したがって、次の解決策が有効かどうか疑問に思います: 基本クラスのデストラクタでのみ CRTP を使用します。

template<class TCRTP> class Base
{
    ~Base() {delete static_cast<TCRTP*>(this);}
}

ここで、TCRTP は DerivedA、B、または C になり、公開継承を行います。それは完全に大丈夫ですか、それとも問題がありますか?

どうもありがとうございました。

4

2 に答える 2

8

あなたのデストラクタは間違いなく間違っています。deleteクラスのデストラクタは、オブジェクトのメモリを保持しませんし、保持してはなりません。

仮想関数を使用しないパブリック継承に対する異議は何ですか? 誰かがベース ポインターを介して派生オブジェクトを誤って削除するのを防ぐ方法が (少なくとも) いくつかあります。1 つは、ベース デストラクタを作成することprotectedです。

もう 1 つは、派生クラスの動的に割り当てられたインスタンスを直接 .xml に詰め込むことshared_ptrです。これは次の場合もありますshared_ptr<Base>

std::shared_ptr<Base> foo(new DerivedA(...));

shared_ptrには引数の型をキャプチャするテンプレート コンストラクターがあるため、Base*ポインターは にDerivedA*関連付けられた削除関数で変換され、shared_ptr正しく削除されます。からポインターを抽出し、shared_ptrそれを として削除しようとするほど愚かな人はいませんBase*

もちろん、仮想関数がない場合、派生クラス間の唯一の違いがコンストラクターで設定したものである場合にのみ、このトリックが本当に役立ちます。Base*そうしないと、ポインターを からダウンキャストする必要がshared_ptr生じます。この場合、最初に ashared_ptr<DerivedA>を使用する必要がありました。

于 2012-05-25T13:36:58.847 に答える
1

の実装内のようなコードを使用していることがわかりIUnknown::Releaseましたが、デストラクタでは決して使用されませんでした。デストラクタはBase、派生オブジェクトが破棄された後にのみ実行され、deleteその時点で派生オブジェクトを試行することは未定義の動作です。その特定のケースでは、無限再帰が得られると確信しています。

于 2012-05-25T13:49:18.930 に答える