两个类(A,B) - B有一个指向A类非静态方法的指针

时间:2012-02-10 10:19:29

标签: c++ pointers

我有两个班级对自己的班级A,班级B一无所知。

A类称为ENGINE, B类称为GUI。

我希望GUI类有一个指向ENGINE类中函数的指针,这样当GUIControl上发生事件时,它会使用两个参数(int,int)调用ENGINE成员函数。

以下是我想要的方式:

class CGUIManager
{
public:
    void SetControlCallback(void(*pFunctionPointer)(int,int) );

private:
    void (*m_pControlCallbackFunction)(int,int) ;
};
void CGUIManager::SetControlCallback(void(*pFunctionPointer)(int,int) )
{
    if(pFunctionPointer)
        m_pControlCallbackFunction = pFunctionPointer;
}

class CEngine
{
private:        
    void GUIControlsCallback(int iControlID, int iControlMessage);
    CGUIManager *pGUI;
};

现在在初始化ENGINE时,我想调用:

//Set Controls Callback to CEngine Method 
pGUI->SetControlsCallback( GUIControlsCallback );

要在CGUIManager类中注册一个回调,它指向CEngine类中的方法。

我该怎么做?

提前致谢。

4 个答案:

答案 0 :(得分:4)

我建议使用一个接口(或类似的东西),如果你希望它是oo而不是函数指针(必须指向一个静态成员btw)

class IGuiCallback
{
public:
    virtual void  GUIControlsCallback(int iControlID, int iControlMessage)=0;
};

class CGUIManager
{
public:
    void SetControlCallback(IGuiCallback*);

private:
    IGuiCallback* m_pCallback;
};

class CEngine:public IGuiCallback
{
public:
    void GUIControlsCallback(int iControlID, int iControlMessage);

private:
    CGUIManager *pGUI;
};

然后在引擎中:

pGUI->SetCallback(this);

我的代码中可能存在一些语法错误,但你应该得到图片

答案 1 :(得分:0)

指针到成员函数不是C ++中的函数指针。

要稍后调用您的回调(使用提供的SetControlsCallback签名),调用者需要有一个有效的CEngine实例。您可以通过将指针绑定到CEngine到GUIControlsCallback:

来实现
CEngine* pEngine; // initialized somewhere
pGUI->SetControlsCallback(std::bind1st(pEngine, GUIControlsCallback));

如果你使用Boost或C ++ 11,你最好使用他们的绑定版本(分别为boost::bindstd::bind)。

答案 2 :(得分:0)

最简单的方法是使用std::function<void(int, int)作为已注册回调的类型:此对象可用于调用任何可用两个int调用的函数[object]。特别是,它可以调用实际上有三个参数的成员函数CEngine::GUIControlsCallback(int, int)

  1. 类型int
  2. 的成员函数的两个明显参数
  3. 指向对象的隐式指针(变为this
  4. 这样做的方法是构造一个函数对象,它为第一个参数提供一个指向CEngine对象的指针,并采用两个整数:

    struct CEngine_bind {
        CEngine_bind(CEngine* engine): engine_(engine) {}
        void operator()(int i0, int i1) { this->engine_->GUIControlsCallback(i0, i1); }
        CEngine* engine_;
    };
    

    或者,您可以使用std:bind()创建一个适当绑定的函数:

    CEngine engine; // ... wherever this object is coming from)
    std::function<void(int, int)> callback(std::bind(&CEngine::GUIControlsCallback, &engine,
        std::placeholders::_1, std::placeholders::_2));
    

    ...然后将callback对象设置为回调。这个对象简单地被称为传递两个整数参数,这将导致被引用对象上的成员函数被调用:

    callback(10, 20);
    

    会打电话给

    engine.GUIControlsCallback(10, 20);
    

    std::function<void(int, int)>是可复制的,即您可以轻松地将其存储在CGUIManager课程中。

答案 3 :(得分:0)

如果你能够改变CGUIManager类的接口,我建议你将它概括为使用boost::function<void(int, int)>(或std::function,如果用C ++ 11编写)而不是函数指针。< / p>

如果你不能,不幸的是你是糟糕设计的受害者。使用函数指针的C风格回调通常允许某种void*用户数据参数携带绑定到回调的任何其他信息 - 在这种情况下,您的CEngine指针可以转换为void *和可以编写一个自由函数包装器来将void*强制转换回CEngine。但是,如果您能够更改回调接口,则使用boost / STL功能是一种优秀的技术。