我有两个班级对自己的班级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类中的方法。
我该怎么做?
提前致谢。
答案 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::bind
或std::bind
)。
答案 2 :(得分:0)
最简单的方法是使用std::function<void(int, int)
作为已注册回调的类型:此对象可用于调用任何可用两个int
调用的函数[object]。特别是,它可以调用实际上有三个参数的成员函数CEngine::GUIControlsCallback(int, int)
:
int
this
)这样做的方法是构造一个函数对象,它为第一个参数提供一个指向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功能是一种优秀的技术。