2017-05-04 5 views
0

プロジェクト内でSubject-Observerパターンを成功させて使用しています。 Subject-Observerとメッセージタイプの数が5以上に増えたので、私はそれぞれ同じコードパターンを複製しています。 Subject-Observerパターンのクラステンプレートに切り替えようとしています。しかし、私は、私は(努力にもかかわらず)を解決することができなかったコンパイルエラーに貼り付けています:C++エラー:(基底クラステンプレートから)サブクラスへの無効な変換

Building file: ../main.cpp 
Invoking: GCC C++ Compiler 
g++ -std=c++0x -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp" 
../main.cpp: In instantiation of ‘Observer<T_subject, T_message>::~Observer() [with T_subject = RotationSubject; T_message = long unsigned int]’: 
../main.cpp:49:7: required from here 
../main.cpp:39:15: error: invalid conversion from ‘Observer<RotationSubject, long unsigned int>* const’ to ‘RotationObserver*’ [-fpermissive] 
    ~Observer(){ subject->UnregisterObserver(this); } 
     ^
../main.cpp:10:7: error: initializing argument 1 of ‘void Subject<T_observer, T_message>::UnregisterObserver(T_observer*) [with T_observer = RotationObserver; T_message = long unsigned int]’ [-fpermissive] 
    void UnregisterObserver( T_observer* observer){ 
^
make: *** [main.o] Error 1 

最小限の作業のコード例です:

#include <vector> 

template <class T_observer, typename T_message> class Subject 
{ 
public: 
void RegisterObserver(T_observer* observer){ 
    observers.push_back(observer); 
} 

void UnregisterObserver( T_observer* observer){ 
    for (auto itr = begin(observers); itr != end(observers); itr++){ 
     if (*itr == observer){ 
      itr = observers.erase(itr); 
      if (itr == observers.end()) break; 
     } 
    } 
} 

void NotifyObservers(T_message message){ 
    for(auto const& itr : observers){ 
     itr->ReceiveMessage(message); 
    } 
} 

std::vector < T_observer * > observers; 
}; 


template <class T_subject, typename T_message> class Observer 
{ 
public: 

Observer(T_subject* subject) 
: subject(subject) 
{ 
    subject->RegisterObserver(this); 
} 

~Observer(){ subject->UnregisterObserver(this); } 

virtual void ReceiveMessage(T_message message) {}; 
// Observer sub-classes define ReceiveMessage 

T_subject* subject; 
}; 

class RotationSubject;// forward declaration prevents circular dependency 

class RotationObserver : public Observer< RotationSubject, unsigned long> 
{ 
public: 
RotationObserver(RotationSubject* rotation_subject); 
}; 

class RotationSubject : public Subject< RotationObserver, unsigned long> 
{ }; 

int main(int argc, char * argv[]){ 
RotationSubject* pRotSubject = new RotationSubject(); 
RotationObserver* pRotObserver = new RotationObserver(pRotSubject); 
pRotObserver->~RotationObserver(); 
return 0; 
} 

意図は、これらのベースから派生するサブクラスを定義することですここにはRotationSubjectRotationObserverと表示されています。タイプ識別子T_observerおよびT_subjectの動機付けは、どのサブクラスが対になるかを特定することである。 RotationObserversは、RotationSubjectsを観察し、ローテーションメッセージタイプ(T_messageはこの例ではunsigned long)を受信する必要があります。

私が正しくエラーメッセージを読めば、Observer<RotationSubject, long unsigned int>* constないRotationObserver*、またはコンパイラが変換する方法を認識していないです。

循環依存性とconstを原因として探求しましたが、成功しませんでした。

このエラーメッセージの原因を理解し、可能であれば修正するための最小限の編集を手伝ってください。これが私の主な質問です。

私は全く異なるデザインと改善のための提案をしています。

答えて

1

: (https://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ) (Template based Subject Observer pattern - Should I use static_cast or dynamic_cast) (Should I use dynamic cast in the subject observer pattern with templates

次のコードは動作する修正されたバージョンです。それは最初のリンクから派生したものです。 @BoundaryImpositionの応答では、テンプレートサブジェクト:: NotifyObservers()メソッドのstatic_castを使用して、Subjectサブクラスへのポインタを取得します。私はこのコンセプトに100%満足しているわけではありませんが、機能します。私の理解によれば、魔法のソースは、SubjectCuriously Recurring Template Patternの使用です。具体的にはclass Temperature : public Subject<Temperature>(分かりやすくするために2番目のテンプレート識別子が削除されています)。以前は私がclass RotationSubject : public Subject<RotationObserver>を使用していたのに対し、これはまったく異なる継承です。 ObserverサブクラスPanicSirenも異なる継承を持ちます。

私のテンプレートはObserver ctorとdtorにRegisterObserverUnregisterObserverを移動することに注意してください。私はそれが好きなだけ、必要ではありません。また、さまざまなメッセージタイプを可能にするメッセージタイプテンプレート識別子T_messageを追加しました。

意図した設計が大規模な書き直しなしで達成されたため、私は満足しています。

#include <vector> 
#include <iostream> 

template <typename T_subject, typename T_message> class Observer{ 
public: 
    Observer(T_subject* subject) : subject(subject) { subject->RegisterObserver(*this); } 
    virtual ~Observer() { subject->UnregisterObserver(*this); } 
    virtual void ReceiveMessage(T_subject* subject, T_message message) = 0;// =0 requires subclasses to define 
    T_subject* subject; 
}; 

template <class T_subject, class T_message> class Subject{ 
public: 
    virtual ~Subject() {} 
    void NotifyObservers(T_message message){ 
     typename std::vector<Observer<T_subject,T_message> *>::iterator it; 
     for (it=m_observers.begin(); it!=m_observers.end(); ++it){ 
      T_subject* this_subject_subclass = static_cast<T_subject*>(this);// pointer to _subclass_ type, curiously not yet defined ;) 
      (*it)->ReceiveMessage(this_subject_subclass, message); 
     } 
    } 

    void RegisterObserver(Observer<T_subject,T_message> &observer){ 
     m_observers.push_back(&observer); } 

    void UnregisterObserver(Observer<T_subject,T_message> &observer){ 
     for (auto itr = begin(m_observers); itr != end(m_observers); itr++){ 
      if (*itr == &observer){ 
       itr = m_observers.erase(itr); 
       if (itr == m_observers.end()) break; 
      } 
     } 
    } 
private: 
    std::vector<Observer<T_subject,T_message> *> m_observers; 
}; 

class Temperature : public Subject<Temperature,unsigned long> {}; 

class PanicSiren : public Observer<Temperature,unsigned long> 
{ 
public: 
    PanicSiren(Temperature* subject) 
    : Observer<Temperature,unsigned long>::Observer(subject) {} 
    void ReceiveMessage(Temperature *subject, unsigned long message){ 
     std::cout << "Temperature changed to " << message <<", sounding the siren" 
       << std::endl; 
    } 
}; 

int main(int argc, char * argv[]){ 
    Temperature* temp = new Temperature(); 
    PanicSiren* panic = new PanicSiren(temp); 
    temp->NotifyObservers(42); 
    return 0; 
} 
2

あなたはconst修飾子を削除しています。あなたはconst_castなしでそれをすることはできませんし、正当な理由もあります。

「間違った」方向にも変換しようとしています。 Observer< RotationSubject, unsigned long>が必ずしもRotationObserverであるとは限りませんが、逆の場合もあります。あなたはdynamic_cast(またはstatic_castと約束)と一緒に動作させることができます。さらに具体的テーマ、オブザーバーパターンをテンプレート化に関連するいくつかの有用なリンクを上げサーチし

+0

ありがとうございます。答え:両方の問題を正しく特定しました。継承と型キャスト'static_cast'は簡単に追加できましたが、継承パターンを修正するにはもう少し読んでいました。 –

+0

@TysonHilmer:うれしいよ! –

関連する問題