这几天做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方法,有不会引起互相包含的问题了
运行结果如下