C ++(C3867)将成员函数传递给函数调用

时间:2010-01-03 18:10:44

标签: c++

我正在尝试将成员函数作为参数传递。基本上我有一个名为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关键字。

提前致谢!

6 个答案:

答案 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节。