前向声明不完整类型,递归

时间:2017-02-01 15:12:43

标签: c++

我有两个类Observer和Subject以及ObserverA,ObserverB正在扩展Observer(用于实现Observer DP)。

在Subject中我有一个指向Observer类的指针向量:

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中,我还有一个主题:

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;    
    }
};

在声明类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;
   ^

我有一个指向Observer的指针向量,在Subject类中,我转发声明的Obsever类,Observer类知道Subect,为什么我仍然有错误?

1 个答案:

答案 0 :(得分:3)

Subject::notifyAll的实现移动到.cpp文件中(事实上,对所有成员函数实现都这样做) - 比如subject.cpp文件。然后在包含Observer类定义的头文件中保留Subject的前向声明,并在subject.cpp中保留#include "observer.hpp"

头文件中的前向声明已足够,因为类定义仅引用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();
  }
}

此外,您的观察者实现可以改进很多。例如。 :

  • 请勿在{{1​​}}中保留Subject。你可能会有同一个观察者的多个科目,但更重要的是:观察者不需要跟踪科目。
  • 不要将ObserverSubject构造函数中的Observer相关联。这只会让你每个观察者都有一个主题。而是将Observer附加到Observer构造函数(或其他成员函数)中的Subject
  • 当你不想复制时,
  • 不会超过价值。相反,通过引用传递(例如Subject)。