2017-02-01 9 views
0

ObserverとSubjectの2つのクラスObserverA、ObserverBがObserver(Observer DPを実装するために)を拡張しています。似前方宣言不完全型、再帰

class Observer { 
protected: 
    Subject subj; 
public: 
    virtual void update() {}; 
}; 

ObserverA、ObserverB:

class ObserverA: public Observer { 
public:  
    ObserverA(Subject s) { 
     subj = s; 
     s.attach(this); 
    } 

    virtual void update() { 
     std::cout << "Update A, state subj: " << subj.getState() << std::endl;  
    } 
}; 

オブザーバーで
class Subject { 
    std::vector<Observer*> obs; 
    int state; 
public: 
    Subject(): state(0) {} 

    void notifyAll() { 
     for(std::vector<Observer*>::iterator it = obs.begin(); it != obs.end(); it++) 
     { 
     (*it)->update(); 
     } 
    } 
} 

... 
}; 

、私はまた、件名を持っている:件名で

私はObserverクラスへのポインタのベクトルを持っています

Subjectクラスを宣言する前に、Observerクラスの前方宣言を追加しました。しかし、私はコンパイルエラーを取得しています:

Observer.h: In member function ‘void Subject::notifyAll()’: 
Observer.h:27:17: error: invalid use of incomplete type ‘class Observer’ 
      (*it)->update(); 
       ^
Observer.h:7:7: error: forward declaration of ‘class Observer’ 
class Observer; 
^

私はオブザーバーへのポインタのベクトルを持って、Subjectクラスでは、私は前方にオブザーバークラスとObserverクラスは、私はまだエラーを持っていない理由Subect、知っていると宣言しましたか?

+0

あなたが実際に* *クラスの機能を使用できるようにしたい場合は、あなたがそれの完全な定義を必要としています。前方宣言しかない場合、コンパイラはどのメンバ関数に実際にどのようなことがあるかを実際に知っていますか? –

+0

IMOでは、同じ問題について「重複した質問」と2つの質問が異なります。解決策を知っているプログラマはすぐに答えを知るでしょうが、新しいプログラマーはそうしないでしょう。なぜなら、彼はなぜ答えを尋ねているのですか? –

答えて

3
(実際には、すべてのメンバ関数の実装のためにそう).cppファイルに Subject::notifyAllの実装を移動

- subject.cppファイルを言います。次に、Subjectクラス定義、およびsubject.cpp内に#include "observer.hpp"を含むヘッダーファイルにObserverの前方宣言を保持します。

クラス定義ではObserver*しか参照していないので、ヘッダーファイルでは前方宣言で十分です。一方、.cppファイルは、Observerインスタンスのメンバ関数を呼び出すため、完全なObserverクラス定義を参照する必要があります。だから、

// subject.hpp 
#include <vector> 

class Observer; 

class Subject { 
    std::vector<Observer*> obs; 
    int state; 
public: 
    Subject(): state(0) {} 

    void notifyAll(); 
}; 

と:

// subject.cpp 
#include "subject.hpp" 

#include "observer.hpp" 

#include <vector> 

void Subject::notifyAll() { 
    for(std::vector<Observer*>::iterator it = obs.begin(); it != obs.end(); it++) 
    { 
    (*it)->update(); 
    } 
} 

はまた、あなたのオブザーバーの実装はかなり改善することができます。例えば。 :

  • ObserverにはSubjectを入れないでください。同じオブザーバーに対して複数のサブジェクトが存在する可能性がありますが、より重要なことはオブザーバーがサブジェクトを追跡する必要がないことです。
  • ObserverコンストラクタでObserverSubjectをリンクしません。そうすれば、オブザーバーごとに1つの被験者しか持たせることができません。代わりに、Subjectコンストラクタ(または別のメンバ関数)内のSubjectObserverを添付します。
  • コピーを作成したくない場合は値渡ししないでください。代わりに、参照渡し(例:const Subject&)。
+0

Subject定義の前にObserver定義を移動して解決し、ObserverではSubjectへのポインタを使用しました。 –

+1

@georgiana_e:コードを別々のファイルに分割することを本当に考慮する必要があります。あなたの人生をもっと楽にしてくれるでしょう。 –