2

这是我的代码和要求:

我有 2 个 A 和 B 类,它们没有任何继承。我用A类的一种方法调用B类的一种方法,那么B类的方法应该回调A类的方法之一来执行回调。

部分代码:

类A.h:

#include "classB.h"

class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

类A.cpp:

#include "classA.h"
classA::classA()
{
  pClassB = new classB();
}

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction();
}

类B.h:

class classB
{
  public:
  classB();
  void callFunction();
}

B类.cpp:

#include "classB.h"
classB::classB()
{
}

void classB::callFunction()
{
   // I should call classA's callback here!
}

问题是,我不能在 classB.h 中包含 classA.h,因为它会在其他地方导致一些编译问题(我无法解决)。我不能将 classB 作为 classA 的子类(如果可以,我只需要这样做classA::callBack())。那么有没有办法解决这种情况呢?

更新:这就是我修改的内容:

class classB
{
  public:
  classB(classA& pCallBack);
  void callFunction();
  void (classA::*m_callback)(void);
};

classA::classA()
{
  pClassB = new classB(*this);
}

classB::classB(classA& pCallBack)
{
  m_callback = pCallBack;
}

我试图保存指针,但也失败了。它说“从不兼容的类型分配”......它有什么问题?

4

3 回答 3

7

实际上,相互包含两个头文件是一种循环依赖,编译器无法解决。有不同的方法可以解决这个问题,我在下面描述其中的三种。

使用前向声明

打破循环依赖最直接的方法是使用前向声明。前向声明仅告诉编译器给定名称表示一个类。如果您只使用指向该类型的指针/引用就足够了,因为在这些情况下,编译器不需要该类型的完整定义。所以你可以像这样改变classA.h

class classB;

class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

这样,标头不再依赖于classB.h。当然,您现在需要classA.cpp#include中的该标头:

#include "classA.h"
#include "classB.h"
...

介绍一个界面

另一种方法是向 引入一个超接口(或在 C++ 中,一个抽象超类)classA,然后让我们classB只看到:

回调.h:

class callback
{
  public:
  virtual void callBack() = 0;
};

类A.h:

#include "callback.h"

class classB;

class classA : public callback
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

类B.h:

#include "callback.h"

class classB
{
  callback& m_a;
public:
  classB(callback& a);
  void callFunction();
};

B类.cpp:

#include "classB.h"

classB::classB(callback& a) : m_a(a) {}

classB::callFunction()
{
  m_a.callBack();
}

如您所见,这种方式classB不依赖classA于任何方式。这实际上允许您稍后classA用 的任何其他实现替换callback,而无需触及classB' 的定义。

引入函数指针

另一种可能性是定义/使用与 匹配的函数指针类型classA::callBack(),并且仅将指向回调函数的指针传递给classB,而不是整个classA对象。虽然,这只适用于static方法无缝 - 对于非静态函数,您仍然需要一个classA对象进行调用。

更新

您在修改后的代码中混合了两种方法(传递对象classA或仅传递函数指针)。最好一次坚持一个。第一种方法更简单,如下所示:

class classA;

class classB
{
  classA& m_a;
public:
  classB(classA& a);
  void callFunction();
};

classB::classB(classA& a) : m_a(a) {}

classB::callFunction()
{
  m_a.callBack();
}

对于非静态成员函数,函数指针方法会更复杂,因为您需要函数指针调用它的对象。@Tadeusz 的回答中显示了另一种方法。

于 2012-04-20T10:13:28.000 回答
3

如果你只需要一个回调,那么B类就不需要知道A类的任何事情。只需传递一个回调。我将提供一个提升(C++ 11 之前)的解决方案:

类B.h:

#include <boost/function.hpp>

class classB
{
    void callFunction(boost::function<void()> callback);
}

B类.cpp

void classB::callFunction(boost::function<void()> callback)
{
    callback();
}

类A.cpp:

#include <boost/bind.hpp>

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction(boost::bind(&classA::callBack, this));
}
于 2012-04-20T10:29:03.390 回答
2

使用前向声明,例如:

类A.h:

class classB; // forward declaration
class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

类B.h:

class classA; // forward declaration
class classB
{
  public:
  classB();
  void callFunction(classA& a);
  // could store pointer to classA instance here instead
}

只要您仅在 classA.h 中使用指向 classB 的引用或指针,此方法就可以工作,反之亦然。

类A.cpp:

#include "classA.h"
#include "classB.h"
classA::classA()
{
  pClassB = new classB(); // could pass 'this' to classB here instead
}

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction(*this);
}

B类.cpp:

#include "classB.h"
#include "classA.h"
classB::classB()
{
}

void classB::callFunction(classA& a)
{
   a.callback();
}
于 2012-04-20T10:14:55.550 回答