我正在尝试将成员函数作为参数传递。基本上我有一个名为AboutWindow的类,标题看起来像这样(为简洁而修剪):
class AboutWindow
{
private:
AboutWindow(void);
~AboutWindow(void);
public:
int AboutWindowCallback(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2);
};
在源代码中我试图将AboutWindowCallback成员函数作为(指向/引用)函数传递。
它看起来像这样:
XPAddWidgetCallback(widgetId, this->AboutWindowCallback);
但我收到以下IntelliSense警告:
指向绑定函数的指针可能只是 用于调用函数
是否可以将成员函数传递给XPAddWidgetCallback。注意它必须是该特定实例的特定函数,因为在AboutWindowCallback函数内部,使用了this关键字。
提前致谢!
答案 0 :(得分:3)
我假设你在这里使用x-plane。
不幸的是,XPAddWidgetCallback期望以
的形式进行回调int callback(XPWidgetMessage inMessage, XPWidgetID inWidget,
long inParam1, long inParam2)
您提供了一个类成员函数。如果这是一个全球功能,它将起作用。所以这个:
class AboutWindow
{
private:
AboutWindow(void);
~AboutWindow(void);
};
int AboutWindowCallback(XPWidgetMessage inMessage, XPWidgetID inWidget,
long inParam1, long inParam2);
是对的。
但是,必须拥有全局函数,如x-plane上的noted in this thread一样不好。
为避免这种情况,请查看随x-plane提供的Wrapper类示例“XPCWidget.cpp”,或使用tr1 / boost bind来包装回调。
XPAddWidgetCallback( std::tr1::bind( &AboutWindow::AboutWindowCallback, this ) );
您还可以制作有问题的功能static
:
class AboutWindow
{
private:
AboutWindow(void);
~AboutWindow(void);
static int AboutWindowCallback(XPWidgetMessage inMessage, XPWidgetID inWidget,
long inParam1, long inParam2);
};
答案 1 :(得分:1)
由于各种原因,您无法传递非静态(即绑定)成员函数的地址。您可以改为传递this
指针,或者创建一个存储此this
指针的函数对象,并知道要调用哪个方法,即:
struct CallAboutWindowCallBack{
CallAboutWindowCallBack(AboutWindow* that)
: m_that(that){
}
int operator()(XPWidgetMessage msg, XPWidgetID wdg, long p1, long p2){
return m_that->AboutWindowCallBack(msg, wdg, p1, p2);
}
AboutWindow* m_that;
};
然后:
XPAddWidgetCallback(widgetId, CallAboutWindowCallBack(this));
答案 2 :(得分:1)
您可以获取成员函数的地址,但需要将其指定给成员函数的指针:
int (AboutWindow::*func)(XPWidgetMessage, XPWidgetID, long, long);
func = &AboutWindow::AboutWindowCallback;
成员函数指针只是指向成员函数的指针,但对实例一无所知。要调用它,您需要提供该对象的实例:
AboutWindow aw;
(aw.*func)(msg, id, l1, l2);
AboutWindow *paw = &aw;
(paw->*func)(msg, id, l1, l2);
因此,成员函数指针与常规函数指针不兼容。除非您调用的代码知道您正在传递成员函数,否则您无法使用它们。
您需要做的是使用非成员函数作为成员函数的thunk。类似的东西:
int thunk(XPWidgetMessage msg, XPWidgetID id, long l1, long l2)
{
paw->AboutWindowCallback(msg, id, l1, l2);
}
这里的问题是如何访问您正在使用的对象。你可以使用全局虽然不是很干净。理想情况下,此API允许您将两个long中的任何一个用作上下文指针。在这种情况下,您将指针传递给AboutWindow实例,然后将其取回:
int thunk(XPWidgetMessage msg, XPWidgetID id, long l1, long l2)
{
AboutWindow *paw = reinterpret_cast<AboutWindow *>(l2);
paw->AboutWindowCallback(msg, id, l1, l2);
}
答案 3 :(得分:1)
通常,回调至少会有一个用户指定的参数传递给回调函数。你只需要将它作为指向对象的指针。然后,您需要一个使用此指针的C回调函数,并调用正确的方法。
不幸的是,XPlane似乎没有这个功能 但是您可以使用窗口小部件注册一个值,然后可以在回调中使用它。
不幸的是,它不使用void *参数但是很长,所以从技术上说它不可移植(但实际上它会起作用,尽管你应该在构建系统中添加一个检查)。
extern "C" int Call_AboutWindowCallback_AboutWindow(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2);
int Call_AboutWindowCallback_AboutWindow(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2)
{
long awptr = XPGetWidgetProperty(inWidget,1101,NULL);
if (awptr != NULL)
{
AboutWindow* aw = reinterpret_cast<AboutWindow*>(awptr);
aw->AboutWindowCallback(inMessage,inWidget,inParam1,inParam2);
}
}
int main()
{
AboutWindow aboutWin;
// Create your widget.
XPSetWidgetProperty(inWidget,1101,reinterpret_cast<long>(&aboutWin));
XPAddWidgetCallback(inWidget,Call_AboutWindowCallback_AboutWindow);
// Use Your Widget.
}
请参阅有关XPWidgetPropertyID的文档以查看要使用的号码。我随机使用了1101种,你应该进行适当的研究:见http://www.xsquawkbox.net/xpsdk/mediawiki/XPWidgetPropertyID
答案 4 :(得分:1)
您可以使用全局映射来分派回调,因为您有XPWidgetID。
static std::map<XPWidgetID, AboutWindow*> mapping;
static int AboutWindowCallback(XPWidgetMessage inMessage, XPWidgetID inWidget, long inParam1, long inParam2) {
return mapping[inWidget]->AboutWindowCallbackMemberFn(inMessage, inWidget, inParam1, inParam2);
}
要添加回调,您只需要重新登记以首先填充地图
mapping[widgetId] = this;
XPAddAddWidgetCallBack(widgetId, &AboutWindowCallback);
我假设XPWidgetID可以用作映射键,并且widget ID和AboutWindow实例之间存在1对1的对应关系。如果不是这种情况,您可能需要修改此解决方案。
答案 5 :(得分:0)
传递函数(或成员函数)时,实质上是传递代码开头的地址。这不是绑定到特定实例(即,同一个类的两个实例不会有不同的代码),因此您无法真正传递特定实例的版本。另外,由于C ++的实现方式,你无法真正获得在多态情况下调用的任何版本。
话虽这么说,可能有更多的OO方法来实现你想要做的事情而不需要求助于指向成员函数。有关详细信息,请查看C++ FAQ的第33.2节。