C ++中的前向声明和循环头包含

时间:2012-11-28 13:15:55

标签: c++

我有两个班级

RequestManager.h

#ifndef REQUESTMANAGER_H
#define REQUESTMANAGER_H

#include "RequestClient.h"
class RequestManager
{
public:
     void AddReqeustItem(RequestClient *req);

private:
 std::list<RequestClient*> m_reqClientContainer;
};
#endif

RequestClient.h

#ifndef REQUESTCLIENT_H
#define REQUESTCLIENT_H

class RequestManager; // Forward declaration to avoid cyclic inclusion.

class RequestClient {
public:
void CreateRequest(RequestManager* pManager)
{
  // ... I am creating a request.
  pManager->AddReqeustItem(req);
};
#endif

在上面的代码中,我在Request客户端类中得到错误未定义的RequestManager。有什么问题,如何解决?

3 个答案:

答案 0 :(得分:5)

您不能使用仅具有前向声明的类型。前向声明用于对编译器说该类型存在但编译器不知道该类型的内容。

我的建议:

  • 在头文件中,我只定义类和函数成员。因此,如果仅使用指针,则可以进行前向声明。
  • 在正文文件中,编写成员函数的代码并包含头文件

答案 1 :(得分:1)

将成员函数定义放在一个#includes两个头文件的源文件中。

或者,如果您仍然希望它是inline(或者它是模板化的),那么在定义所有相关代码之后,将成员函数体的定义放在标题中。在单个头文件的情况下(这在这里有意义):

class B; // forward decl
class A {
  void use(B*);
};

class B {
  void use(A*);
};

void A::use(B*b) { /* ... */ }
void B::use(A*a) { /* ... */ }

注意将代码拆分为文件(几个头文件和一个源代码)只是程序员的一种便利(使代码的其他部分维护和使用更加简单),但是从编译器的角度来看,这并不重要:它只能看到一个大的代码文件(在预处理之后)。因此,您可以自行决定如何将上述布局拆分为标题和源文件。

答案 2 :(得分:1)

您使用方法RequestManager::AddReqeustItem(),但只有RequestManager的前向声明。只有一个前向声明,编译器甚至不知道RequestManager的哪些方法存在。因此,要解决此问题,您必须提供RequestManager的定义,它通常位于头文件中。

CreateRequest()的方法定义移动到cpp文件中,并在那里包含RequestManager.h

RequestManager.cpp:

#include "RequestManager.h"
...
void CreateRequest(RequestManager* pManager)
{
  // ... I am creating a request.
  pManger->AddReqeustItem( req);
}