【问题标题】:Forward declaration incomplete type, recursive [duplicate]前向声明不完整类型,递归[重复]
【发布时间】:2017-06-18 09:36:15
【问题描述】:

我有两个类 Observer 和 Subject 以及 ObserverA、ObserverB,它们扩展了 Observer(用于实现 Observer DP)。

在主题中,我有一个指向观察者类的指针向量:

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

...
};

在观察者中,我也有一个主题:

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,为什么我仍然有错误?

【问题讨论】:

  • 如果你想真正使用一个类的功能,你需要它的完整定义。如果你只有一个前向声明,编译器怎么会知道它有哪些成员函数?
  • IMO,它是不同的“重复问题”和关于同一问题的两个问题。知道解决方案的程序员会立即知道答案是相似的,但新程序员不会,这可能就是他提出问题但尚未阅读答案的原因。

标签: c++


【解决方案1】:

Subject::notifyAll 的实现移动到一个.cpp 文件中(事实上,对所有成员函数实现都这样做)——比如subject.cpp 文件。然后在包含Subject 类定义的头文件中保留Observer 的前向声明,并在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();
  }
}

此外,您的观察者实现可以得到相当大的改进。例如。 :

  • 不要在Observer 中保留Subject。同一个观察者可能有多个主题,但更重要的是:观察者不需要跟踪主题。
  • 不要在Observer 构造函数中将Subject 链接到Observer。那只会让每个观察者有一个主题。而是在Subject 构造函数(或其他成员函数)中将Observer 附加到Subject
  • 当你不想复制时不要传值。而是通过引用传递(例如const Subject&amp;)。

【讨论】:

  • 通过将观察者定义移到主题定义之前解决,并且在观察者中我使用了指向主题的指针。
  • @georgiana_e :你真的应该考虑将你的代码拆分到不同的文件中——你会让你的生活更轻松。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2013-07-09
相关资源
最近更新 更多