【问题标题】:C++ : Class & callbacks issueC++:类和回调问题
【发布时间】:2012-04-20 10:08:44
【问题描述】:

这是我的代码和要求:

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

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

【问题讨论】:

  • C 没有类、成员函数和运算符 new。 C标签不合理。

标签: c++


【解决方案1】:

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

使用前向声明

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

class classB;

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

这样标题就不再依赖于classB.h了。当然,你现在需要#include classA.cpp 中的那个头文件:

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

介绍界面

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

回调.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。这实际上允许您稍后用callback 的任何其他实现替换classA,而无需触及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 的回答中显示了它的另一种选择。

【讨论】:

  • 感谢您的快速回复,但不幸的是,在我的情况下,我无法将任何内容传递给 B 类。您的第一个解决方案应该可行,但我想知道是否有更好的解决方案:)
  • @Syhou 假设回调是同步的(如果不是),提供中间接口是“正确”的答案。
  • 所以,你基本上做了一个前向声明(正如我指出的那样),以解决你需要放置引用或指针的事实,例如classB 在 classA 的标题中,反之亦然。不需要超类本身来避免循环引用。
  • 顺便说一句,最好尽可能使用 前向声明 - 它可以加快编译速度,尤其是在您更改其中一个标题时。
  • @Syhou,如果你不能将任何东西传递给classB,它应该如何知道回拨到哪里?它需要有一个函数指针或一个对象引用/指针才能进行回调。这可以作为(构造函数/方法)参数传递,或者通过全局变量提供(这很难看,不推荐)。
【解决方案2】:

如果你只需要一个回调,那么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));
}

【讨论】:

    【解决方案3】:

    使用前向声明,例如:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多