関数ポインタとコールバック

私は、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
};

and 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の最後の関数からコールバックを返すと、下線が引かれ、エラーが表示されます。

エラー:戻り値の型が関数の型と一致しません。

私は、それが要求しているオブジェクトのように見えないものを返すために、その関数に強制しようとしているということがわかっています。しかし、それは単なる機能であり、私がメインクラスでそれを行うことができれば、それは大丈夫だろう。私の問題は、selectROI関数へのポインタをselectHandlerが返すことで、別のクラスで使用できるようにすることです。

0

2 答え

selectROI()メソッドは静的ではないため、最初の引数として暗黙の this パラメータが必要です。それを静的にしようとすると、実際にC APIに渡す場合は、実際に extern "C" を渡す必要がありますが、完全に適切かつ移植可能なすべての機能ポインタ。これは次のような簡単な転送機能です。

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

次に、C ++クラスのメソッドを静的でなく(クラスメンバー変数にアクセスできるように)する場合は、 cvSetMouseCallback()の3番目の引数としてMouseHandlerオブジェクトへのポインタを渡すだけで済みます。あなたはあなたのコールバックでそれを受け取るでしょう、そして、これは次のように見えます:

extern "C" void selectROI( int event, int x, int y, int flags, void *param )
{
    static_cast(param)->selectROI( event, x, y, flags);
}
1
追加された
return selectROI;十分なextern "C"関数へのポインタを返します。 selectHandler()を呼び出してハンドラを取得する人は、その結果をMouseHandlerオブジェクトのアドレスとともに渡す必要があることを知る必要があります。 MouseHandlerに代わりに自身を登録するように指示する関数があると考えるかもしれません。
追加された 著者 John Zwinck,
selectROI関数は、使用しているC APIに渡すのに適しているように、C呼び出し規約を使用した単なる薄いラッパーです。それが行うのはあなたのクラス型への "param"ポインタをキャストすることです(クラスへのポインタをコールバック登録のC関数に渡す場合、このキャストは問題ありません)。これまでと同じように(非静的な)クラスメソッドでコードを記述します。言い換えれば、私のselectROI()関数には完全なことがあります。あなたはその本体に何も追加する必要はありません。
追加された 著者 John Zwinck,
C ++クラスメンバ関数をC関数ポインタに「変換する」ことはできません。 C ++のオブジェクトポインタをC void *の中に隠しておくことはできますが、C ++の関数ポインタを隠すことはできません(技術的には静的なクラスでもありませんので、void *からクラスインスタンスのキャストを行うラッパー関数が必要です)メソッドですが、特に非静的なものではありません)。
追加された 著者 John Zwinck,
私はそれをしましたが、どのようにselectHandler関数から関数ポインタを返すことができますか?
追加された 著者 Nicolas Epaminonda,
selectHandlerメソッドはまだselectROIを返すことができません。なぜなら、CvMouseCallbackは実際には関数へのポインタにすぎません。 static_castの目的は何ですか? selectRoi関数でどのように使うべきですか?その機能の中で起こっていることはすべて下にあるはずですか?ありがとう
追加された 著者 Nicolas Epaminonda,
私は、あなたが何を言おうとしているかを完全に理解しているとは言えませんが、私はそのほとんどを得ています。私はselectROI関数に何か特別な機能を持たせて、このメンバ関数をCvMouseCallback関数としてMain.cppにあるcvSetMouseCallbackに渡したいと思います。 static_castは、クラスへのポインタ型変換です。私は、クラスメンバー関数selectROIをCvMouseCallbackに変換してmainに返すか、MouseHandler :: selectROI関数をMainに返してからCvMouseCallbackに変換するかどうかを知りたいだけです。 CvMouseCallbackはhighgui_c.hのtypedefです
追加された 著者 Nicolas Epaminonda,

私はここで 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);

Is not a class member function, while yours is a member of class MouseHそしてler, which means its a different signature そして different parameter list (to accommodate for this). Using static class member function solves it for you.

もちろん、オブジェクトコンテキストデータを静的関数に渡す方法を理解する必要があります。

1
追加された
ありがとうございますが、私はすでに静的関数を試しましたが、コールバックは別のエラーを返します> Error:式は変更可能な値でなければならず、戻りエラーは同じです。
追加された 著者 Nicolas Epaminonda,
ええ、それを解決して...それが動作するかどうかを見てみましょう。ありがとうございました!!!
追加された 著者 Nicolas Epaminonda,
@ニコラス - そのエラーが何であるかを確認して解決してください。
追加された 著者 littleadv,