C ++:Class&回调问题

时间:2012-04-20 10:08:44

标签: c++

这是我的代码&要求:

我有2个班级A& B,他们没有任何遗产。我使用A类的一种方法来调用B类的一种方法。然后B类的方法应该回调A类方法中的一种来执行回调。

部分代码:

classA.h:

#include "classB.h"

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

classA.cpp:

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

void classA::callBack()
{
  return;
}

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

classB.h:

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

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

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

3 个答案:

答案 0 :(得分:6)

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

使用前向声明

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

class classB;

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

这样,标题不再依赖于 classB.h 了。当然,您现在需要{em> classA.cpp 中的#include标题:

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

介绍接口

另一种方法是将超级接口(或C ++,一个抽象超类)引入classA,让classB只看到:

callback.h:

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

classA.h:

#include "callback.h"

class classB;

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

classB.h:

#include "callback.h"

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

classB.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的答案显示了另一种选择。

答案 1 :(得分:3)

如果你只需要一个回调,那么B类就不需要知道关于A类的任何信息。只需传递一个回调。我会给予一个提升(前C ++ 11)解决方案:

classB.h:

#include <boost/function.hpp>

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

classB.cpp

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

classA.cpp:

#include <boost/bind.hpp>

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction(boost::bind(&classA::callBack, this));
}

答案 2 :(得分:2)

使用前向声明,例如:

classA.h:

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

classB.h:

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

只要你只在classA.h中使用classB的引用或指针,反之亦然,这就行了。

classA.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);
}

classB.cpp:

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

void classB::callFunction(classA& a)
{
   a.callback();
}