2016-01-11 5 views
6

私は外部ライブラリを使用しており、オブザーバーがライブラリに属する​​オブジェクトから派生したオブザーバーパターンを作成する必要があります。私はライブラリから基本クラスを変更したいと同時に、この変更不可能な基本クラスへの参照/ポインタのリストを使用する必要があります。この上にライブラリはオブザーバになるオブジェクトのリストを作成します。外部ライブラリから派生したオブジェクトでRTTIを使用する

私が書いたコードは、このとほぼ同等です:

#include <iostream> 
#include <vector> 
#include <memory> 

// This class is from an external library which I don't want to chagne 
class BaseFromLibrary { 
    public: 
    virtual ~BaseFromLibrary() {} 
}; 

class BaseOfObserver { 
    public: 
    void notify() { std::cout << "What-ho!\n"; }; 
}; 

class Observer : public BaseFromLibrary, public BaseOfObserver {}; 

class Subject { 
    public: 
    std::vector<std::shared_ptr<Observer>> observers; 
    void notifyObervers() { 
     for (auto &o : observers) 
      (*o).notify(); 
    } 
}; 

int main() { 
    // This list is constructed by the library and I cannot interfere with that 
    // process 
    std::vector<std::shared_ptr<BaseFromLibrary>> list{ 
     std::make_shared<BaseFromLibrary>(), std::make_shared<Observer>()}; 
    Subject s; 

    for (auto &e : list) 
     if (std::dynamic_pointer_cast<Observer>(e) != nullptr) 
      s.observers.push_back(std::dynamic_pointer_cast<Observer>(e)); 

    s.notifyObervers(); 
} 

それから私は私の他の派生タイプに「対象の意識」を追加するBaseOfObserverを使用しています。このようにして、実装したい特定のオブザーバーごとにifステートメントを繰り返す必要はありません。

うまくいくようですが、デザインミスですか? RTTIメカニズムなしで、そしてライブラリクラスに干渉することなく、オブザーバーリストを構築するより良い方法がありますか?

答えて

0

あなたの問題は、一連の基本ポインタを持ち、特定の派生型であるシーケンスのそのような要素だけを使いたいということです。

dynamic_castはもちろん動作しますが、この場合は必ずしも必要ありません。目的のポインタを別のコンテナに保持する場合は、他のポインタも含むコンテナでポインタを探す必要はありません。

std::vector<Observer *> observers {new Observer()}; 

オブザーバーポインターをコピーすることで、すべてのポインターを含むコンテナーを作成できます。また

std::vector<BaseFromLibrary *> all {new BaseFromLibrary()}; 
all.reserve(all.size() + observers.size()); 
all.insert(all.end(), observers.begin(), observers.end()); 

あなたはコピーせずに、別々の容器内のすべての要素を反復処理したい場合は、Boost.Rangeからboost::joinのようなものを使用することができます。

dynamic_castを使用せずにオブザーバポインタを簡単にコピーできます。もちろん

s.observers.insert(observers.begin(), observers.end()); 

それはあなたがやろうとしているすべてだ場合、あなたは最初の場所での観測者の元の容器としてs.observers使用することもできます。

サイドノートとして、あなたのサンプルプログラムはメモリをリークします。そのような状況を防ぐために、手動によるメモリ管理は避けてください。

+0

私があなたを正しく理解しているなら、私の例から 'list'を分割することを提案しています。私はこれも私ができないことであることを強調するのを忘れているかもしれません。ライブラリはそのリストを独自に構築し、そのプロセスに干渉したくない。私はそれを編集しようとします。 メモリリークが発生しました。 –

関連する問題