這幾天做C++11的線程池時遇到了一個問題,就是類A想要調用類B的方法,而類B也想調用類A的方法
這里為了簡化起見,我用更容易理解的觀察者模式向大家展開陳述
觀察者模式:在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態時,依賴它的對象都會收到通知,並自動更新
觀察者模式中有一個subject和observer
observer向subject注冊成為一個觀察者
當subject發生改變時,它通知所有的觀察者
當一個observer不想作為觀察者時,它會向subject發出請求,將自己從觀察者中除名
注意,在這里是存在一個互相調用的
subject肯定需要知道observer的方法,這樣它才能在狀態發生改變時調用observer的方法通知他們
而當一個observer想要將自己從觀察者中除名的時候,它需要保留一個subjet的引用,並讓subject調用remove方法將自己除名
為了簡化起見
在這里的類圖如下
在java,我們可以這樣實現
import java.util.ArrayList; class Subject { public void change() { for (Observer x :observerList) { x.Show(); } } public void register(Observer o) { observerList.add(o); } public void Remove(Observer o) { observerList.remove(o); } private ArrayList<Observer> observerList=new ArrayList<Observer>(); } class Observer { public void Show() { System.out.println("I konw The Subject is changed"); } public Observer(Subject s) { subject = s; } public void Remove() { subject.Remove(this); } private Subject subject; } public class Observertry { public static void main(String[] args) { Subject s = new Subject(); Observer o = new Observer(s); s.register(o); s.change(); } }
運行結果
而在C++中
如果我們在main.cpp中編寫出以下代碼
#include <iostream> #include <string> #include <vector> using namespace std; class Observer; class Subject; class Observer { public: Observer(Subject *s) { subject = s; } void Remove(Subject *s) { s->Remove(this); } void Show() { cout << "I konw Subject is change" << endl; } private: Subject *subject; }; class Subject { public: void change() { for (vector<Observer*>::iterator it = observerlist.begin(); it != observerlist.end(); it++) { (*it)->Show(); } } void Remove(Observer *o) { observerlist.erase(find(observerlist.begin(), observerlist.end(), o)); } void Register(Observer *o) { observerlist.push_back(o); } private: vector<Observer*> observerlist; }; int main() { Subject s; Observer o(&s); s.Register(&o); s.change(); system("pause"); }
會發現這段代碼無法編譯通過
在vs2013中會有以下error
這是因為雖然有類的成員的前向聲明
但你僅可以定義指向這種裂隙的指針或引用,可以聲明但不能定義以這種不完全類型或者返回類型的參數
而這里你想要在Observer類里調用subject的方法,而subject是在Observer的后面聲明定義的,所以無法調用subject的方法
而C++是沒有對類的函數的前向聲明的
所以我們要有一個方法,讓我們在聲明類Subject時能看到類Observer的聲明
而在聲明類Observer時,能看到類Subject的聲明
所以我們想到將Subject和Observer分別放到兩個文件中去
所以我們有了如下嘗試
subject.h
#pragma once #include "Observer.h" #include <iostream> #include <vector> class Subject { public: void change(); void Remove(Observer *o); void Register(Observer *o); std::vector<Observer*> observerlist; };
observer.h
#pragma once #include <iostream> #include "Subject.h" using namespace std; class Subject; class Observer { public: Observer(Subject *s); void Remove(Subject *s); void Show(); Subject *subject; };
但這一次依舊無法通過編譯
因為我們這里出現了頭文件的互相包含
subject.h中包含了observer.h
observer.h中包含了subject.h
所以正確的方法是把其中的一個的include放到相應的實現文件中即cpp文件中
代碼如下
subject.h
#pragma once #include "Observer.h" #include <iostream> #include <vector> class Subject { public: void change(); void Remove(Observer *o); void Register(Observer *o); std::vector<Observer*> observerlist; };
subject.cpp
#include "Subject.h" void Subject::change() { for (vector<Observer*>::iterator it = observerlist.begin(); it != observerlist.end(); it++) { (*it)->Show(); } } void Subject::Remove(Observer *o) { observerlist.erase(find(observerlist.begin(), observerlist.end(), o)); } void Subject::Register(Observer *o) { observerlist.push_back(o); }
observer.h
#pragma once #include <iostream> using namespace std; class Subject; class Observer { public: Observer(Subject *s); void Remove(Subject *s); void Show(); Subject *subject; };
observer.cpp
#include "Observer.h" #include "Subject.h" Observer::Observer(Subject *s) { subject = s; } void Observer::Remove(Subject *s) { s->Remove(this); } void Observer::Show() { cout << "I know Subject is changed" << endl; }
我們將#include “Subject.h”放到了observer.cpp中
這樣就在observer的實現中就可以看到Subject的聲明,進而調用subject的Remove方法,有不會引起互相包含的問題了
運行結果如下




