1

C++ 言語標準を見て、基本クラスのデストラクタを呼び出さずに、派生クラスのデストラクタのみを呼び出す方法はありますか?

だから、クラスのために

class Base { public: virtual ~Base() {} };
class Derived : public Base { public: ~Derived();};

のようなコードを書くことが可能であれば

Base *basePtr = new Derived();
//do something with basePtr

// Now somehow destroy Derived while keeping Base - call ~Derived() only, 
// line below however will call both ~Derived() and ~Base() - how it can be done?
dynamic_cast<Derived*>(basePtr)->~Derived(); 

したがって、上記のコードの実行後、 basePtr は Base オブジェクトのみを指します。

Base *basePtr = new Base();

さらに、 new Derived() の呼び出しと Derived クラスの破棄の間に basePtr を操作することによって発生した Base オブジェクトへの変更はありますか?

それとも、これは禁止されていて不可能ですか?

4

4 に答える 4

2

いいえ、これは不可能です。標準では、Derived オブジェクトを破棄すると、Base サブオブジェクトを含むオブジェクト全体が破棄されることが要求されます。オブジェクトの有効期間に関する C++ の理解によれば、それ以外のものは破壊ではありません。

達成したいことに応じて、最初に派生からベースをコピーすることを検討してください

std::unique_ptr<Base> basePtr(new Derived());
//do something with basePtr

basePtr.swap(std::unique_ptr<Base> (new Base(*basePtr))); //splice the Base part out of the derived object

//basePtr now points to the spliced Base object.

もう 1 つの方法は、派生がboost::optional(または単に pimpl に) 持つ追加のメンバーを保持し、それをリセットして、基本クラスの部分がまだある「削除された」派生オブジェクトを取得することです。ただし、これは仮想関数のディスパッチには影響しません。

于 2013-04-08T16:01:41.977 に答える
0

派生クラスが基本クラスとは何の関係もない場合を除き、これを行うことはできません。

デストラクタは自動的に呼び出されます。デストラクタを明示的に呼び出すと、未定義の動作が発生する可能性があります。

于 2013-04-08T15:59:31.450 に答える
0

あなたが質問を定式化したように、あなたが求めていることを達成することは不可能です. メモリ リークがない限り、デストラクタを明示的に呼び出しても未定義の動作にならない唯一のケースは、オブジェクトが配置 new によって作成された場合です。それでも、デストラクタを呼び出すと、すべてのメンバーと基本クラスのデストラクタが自動的に呼び出されます。

これはあるべき姿です。そうしないと、正しいコンテナー クラスまたはメモリ マネージャーを作成することが非常に困難になります。

標準では、オブジェクトの有効期間は、デストラクタに入るとすぐに終了すると言われています。基底クラスのオブジェクトにはなりません。それは完全にオブジェクトではなくなります。また、そうでない場合、複数のベースから派生したクラスは、このようなトリックの後でどのような状態になりますか?

最終的に、そのような機能の「必要性」は、設計が悪いことを示しています。あなたのユースケースでは、構成が必要になる可能性が高いと思います。現在の基本クラスのインスタンスを 1 つ保持する新しいクラスと、インターフェースとして機能するいくつかのダミー クラス (へのスマート ポインター) のオプションの交換可能なコンポーネントと新しい共通ベースを保持する新しいクラスで解決できないかどうかを確認します。現在の派生クラスの。そうすれば、ベースに触れることなく、これらのサブ オブジェクトを削除 (および破壊) できます。

于 2013-04-08T16:18:18.790 に答える