3

私は次の問題で箱の外で考えるのに苦労しています。クラス階層があります:

[BaseClass] --> [Win32Class]

[BaseClass] --> [LinuxClass]

[BaseClass] --> [VxWorksClass]

実装クラスは、APIレベルの関数を呼び出します。これらは、基本クラスの純粋仮想関数内で実行されます。

これで、ユーザーがオブジェクトを作成、使用、および終了したら、Done(基本クラスから)関数を呼び出す必要があります。これにより、クリーンアップとリソースの割り当て解除が行われます。このクリーンアップの一部は、いくつかのAPIレベルの関数を呼び出すことです。これらは当然、基本クラスの純粋な仮想であり、派生クラスに実装されます。ここまでは順調ですね。

ここに問題があります。ユーザー明示的に呼び出さDoneないと、リソースが適切に解放されないためにさまざまなメモリリークが発生します。だから、私はそれを簡単にして、破壊時の自動クリーンアップDoneから電話をかけると思いました。~BaseClass()まあ、それほど多くはありません。これらの純粋な仮想を呼び出すのでDone、すべての地獄は解き放たれます。

この問題を回避するためにこれを再設計する方法について何か考えはありますか?

サンプルコード

class BaseClass{ 
  virtual ~BaseClass(){
    Done();
  }
  void Done(){
    // A bunch of OS-independent clean-up logic
    Cleanup();
    // some more OS-independent clean-up logic
  }
  virtual void Cleanup() = 0;
};
class Win32Class : public BaseClass{
  virtual void Cleanup(){
    // call some Win32-specific cleanup code
  }
};
class LinuxClass : public BaseClass{
  virtual void Cleanup(){
    // call some Linux-specific cleanup code
  }
};

==========================================これ
が私の解決策です。ラッパークラスを使用します。またはDoneのデストラクタを呼び出さないでくださいWin32ClassBaseClass

class Win32Wrapper{
public:
  Win32Class* object_;
public:
  Win32Wrapper(){
    this->object_ = new Win32Class;
  }
  ~Win32Wrapper(){
    this->object_->Done();
    delete this->object_;
  }
};

==デストラクタで純粋な仮想を呼び出す方法==

class Base{
public:
  Base(){
  }
  virtual ~Base(){
    Done();
  }
  void Done(){
    Clean();
  }
  virtual void Clean() = 0;
};

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

コンパイラはでPFVの呼び出しについて文句を言わないので、ユーザーはプログラムが機能すると思いますBase::Done()

4

3 に答える 3

2

派生デストラクタにクリーンアップコードを配置できます。

struct Base
{
    virtual ~Base() { }

    void CleanUp() { /* ... */ }
};

struct Derived : Base
{
    virtual ~Derived()
    {
        CleanUp();
    }
};

必要に応じて、さらに仮想関数への呼び出しを非仮想Base::CleanUp()関数に入れて、派生固有の動作を可能にすることもできます(ただし、説明によれば、それは必要ないように思えます)。

于 2012-11-06T23:27:39.320 に答える
0

RAIIイディオムはあなたが探しているものだと思います。

これについての非常に包括的な説明は、http://www.hackcraft.net/raii/にあります。

于 2012-11-06T23:39:03.907 に答える
0

2つのオプションがあります。

  1. のユーザーはBaseClass電話をかける必要がDone()あり、それを行わなかったために発生したバグはすべて彼の責任です。
  2. 派生クラスのそれぞれは、デストロクタで必要なクリーンアップを実行します。BaseClassクリーンアップで関数を使用でき、BaseClass関数は派生クラスによってオーバーライドされる関数を呼び出すこともできます。
于 2012-11-07T21:25:22.320 に答える