【问题标题】:Function pointers and callbacks函数指针和回调
【发布时间】:2011-11-12 22:41:25
【问题描述】:

我正在使用 Microsoft Visual Studio 2010 和 OpenCV 2.3.0 库编写图像处理应用程序。

我有一段代码对我来说是错误的,我不知道如何修复它。我正在实现一个应用程序,其中将同时打开 2 或 3 个窗口,我希望为每个窗口分配不同的 CvMouseCallback 函数。我希望所有这些 CvMouseCallback 函数与另一个函数一起位于不同的类中,该函数根据用户选择返回指向这些函数之一的指针。

我的 Window.h 包含这段代码。

class Window
{
public:
   ... // constructors and destructors
   void setMouseHandler( CvMouseCallback mouseHandler );
private:
   ... // other stuff
};

Window.cpp

#include "stdafx.h"

void Window::setMouseHandler( CvMouseCallback mouseHandler )
{
    cvSetMouseCallback( win, mouseHandler, NULL );
}

现在,MouseHandler.h 文件

class MouseHandler
{
public:
   ...
   CvMouseCallback selectHandler( int option );
   void __cdecl selectROI( int event, int x, int y, int flags, void *param );

private:
   Image *in;
   Window *win;
   void ( CV_CDECL MouseHandler::*callback )( int event, int x, int y, int flags, void *param );
};

最后,在 MouseHandler.cpp 我包含

void __cdecl MouseHandler::selectROI( int event, int x, int y, int flags, void *param )
{
   //do something
}

CvMouseCallback MouseHandler::selectHandler( int option )
{
   callback = (MouseHandler::selectROI);
   return callback;
}

您可能需要的最后一点信息是 OpenCV 库中 CvMouseCallback 的定义

typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);

现在,问题是:当我从 MouseHandler.cpp 中的最后一个函数返回回调时,它带有下划线,并带有错误提示:

错误:返回值类型与函数类型不匹配。

我知道它说的是我试图强加给该函数以返回看起来不像它所要求的对象的东西。但是,它只是一个函数,如果我可以在主类中做到这一点,那就没问题了。我的问题是 selectHandler 如何返回指向 selectROI 函数的指针,以便其他类可以使用它?

【问题讨论】:

    标签: c++ function pointers callback


    【解决方案1】:

    我认为你需要在这里使用static 函数:

    static void __cdecl selectROI( int event, int x, int y, int flags, void *param );
    

    void ( CV_CDECL *callback )( int event, int x, int y, int flags, void *param );
    

    相应地。

    问题是这个定义:

    typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
    

    不是类成员函数,而你的是类MouseHandler的成员,这意味着它的签名和参数列表不同(以适应this)。使用static类成员函数为你解决。

    当然,您必须弄清楚如何将对象上下文数据传递给static 函数。

    【讨论】:

    • 谢谢,但是我已经尝试过静态函数但是回调返回另一个错误>错误:表达式必须是可修改的值,返回错误仍然相同。
    【解决方案2】:

    你的selectROI() 方法,因为它不是静态的,需要一个隐式的this 参数作为它的第一个参数。如果您尝试将其设为静态,您将有更好的机会使其正常工作,但实际上,如果您按原样将其传递给 C API,从技术上讲,您需要传递一个 extern "C" 函数指针,以使一切都完全正确和便携。这可能是一个微不足道的转发函数,如下所示:

    extern "C" void selectROI( int event, int x, int y, int flags, void *param );
    

    然后,如果您希望您的 C++ 类方法不是静态的(因此它可以访问类成员变量),您只需将指向 MouseHandler 对象的指针作为第三个参数传递给 cvSetMouseCallback(),然后您将收到在您的回调中也是如此,然后看起来像这样:

    extern "C" void selectROI( int event, int x, int y, int flags, void *param )
    {
        static_cast<MouseHandler*>(param)->selectROI( event, x, y, flags);
    }
    

    【讨论】:

    • 我已经做到了,但是如何从 selectHandler 函数中返回函数指针?
    • 返回选择ROI;将返回一个指向外部“C”函数的指针就足够了。调用 selectHandler() 来获取处理程序的人需要知道他们应该将其结果与 MouseHandler 对象的地址一起传递。您可能会考虑使用一个函数来告诉 MouseHandler 注册自己。
    • selectHandler 方法仍然无法返回 selectROI,因为它仍然需要一个 CvMouseCallback,它实际上只是一个指向函数的指针。 static_cast 的目的是什么?我应该如何在 selectRoi 函数中使用它?喜欢在上面,然后该函数中发生的任何事情都应该在下面?谢谢
    • selectROI 函数只是一个使用 C 调用约定的瘦包装器,以便适​​合传递给您正在使用的 C API。它所做的只是将“param”指针转换为您的类类型(如果您始终将指向您的类的指针传递给回调注册 C 函数,您知道这种转换是可以的)。然后像以前一样在(非静态)类方法中编写代码。换句话说,我的 selectROI() 函数就是完整的东西——你不需要在它的主体中添加任何东西。
    • 我不能说我完全理解你想说的话,但我确实明白了大部分。我希望我的 selectROI 函数具有一些额外的功能,并且我希望将此成员函数传递给 cvSetMouseCallback,它在 Main.cpp 中作为 CvMouseCallback 函数。 static_cast 是指针到类的类型转换。我只想知道是否有可能将类成员函数 selectROI 转换为 CvMouseCallback 并将其返回给 main 或将 MouseHandler::selectROI 函数返回给 Main 然后将其转换为 CvMouseCallback。 CvMouseCallback 是 highgui_c.h 中的 typedef
    猜你喜欢
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多