クラスメンバー関数の問題への関数ポインター
-
22-07-2019 - |
質問
まず、プログラミングスキルがかなり制限されていることを認めなければなりません。私は(本当に小さな)既存のC ++ OOPプロジェクトを引き継いで、自分のものを押し込もうとしています。残念ながら、私の知識と私はここでいくつかの助けを見つけることを望みます。カメラから画像を取得するためにサードパーティのライブラリ(変更不可)を使用しており、ここではいくつかのプレースホルダー名を使用します。
サードパーティライブラリには、「ThirdPartyGrab」という関数があります。連続ライブグラブを開始し、新しいフレームが到着するたびに呼び出される関数へのポインターを取得します。したがって、通常のCアプリケーションでは次のようになります。
ThirdPartyGrab (HookFunction);
" HookFunction"次のように宣言する必要があります:
long _stdcall HookFunction (long, long, void*);
または" BUF_HOOK_FUNCTION_PTR"として宣言されている
typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);
C ++アプリケーションとクラス" MyFrameGrabber"があります。私が行うすべてをカプセル化する必要があります。そのため、次のようにプライベートメンバーとしてフック関数を挿入します。
ThirdPartyGrab (..., HookFunction, ...);
また、パブリックvoid関数" StartGrab"もあります。私のクラスではグラブを開始する必要があります。内部で私は電話しようとします:
static MyFrameGrabber& instance()
{
static MyFrameGrabber _instance;
return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file
これは(当然のことですが)失敗します。 MyFrameGrabber :: HookFunctionの関数呼び出しで引数リストが欠落しているため、代わりに& MyFrameGrabber :: HookFunctionを使用してポインターを作成する必要があります。ただし、"& MyFrameGrabber :: HookFunction"代わりに、BUF_HOOK_FUNCTION_PTRに変換できないという別のエラーが発生します。
C ++ FAQ関数ポインター私は問題を理解していると思うが、解決策を立てることはできない。フック関数を静的にしようとしましたが、これも変換エラーになります。また、フック関数をクラスの外部に置くことも考えましたが、フック関数の内部でクラス関数を使用する必要があります。別の方法がありますか、または概念全体を変更する必要がありますか?
編集14.01.08: サードパーティのライブラリを変更することはできず、voidポインターはフック関数内で使用されるデータのみであるため、シングルトンの回避策をテストしました。残念ながら、期待どおりに機能しませんでした。...静的関数を別のクラスに含める必要があるかどうかわからないため、「MyFrameGrabber」に入れました。クラス:
long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
ThirdPartyGrab(..., call_hook, ...);
}
cppファイルにはcall_hook関数があります:
MyFrameGrabber (void* x,
const std::string &y, int z,
std::string &zz);
しかし、これにより static MatroxFrameGrabber _instance;
でエラーが発生し、一致する標準コンストラクターが見つかりません。 MyFrameGrabberコンストラクターは次のように見えるため、それは正しいです。
空のコンストラクター MyFrameGrabber();
に入れようとしましたが、これによりリンカーエラーが発生します。シングルトンのMyFrameGrabberコンストラクターに空のパラメーターを渡す必要がありますか?または、別のフッククラスが必要ですか?はいの場合、MyFrameGrabber関数にどのようにアクセスできますか?前もって感謝します。
SECOND EDIT 15.01.08: 変更を適用し、コンパイルしてリンクします。残念ながら、DLLであり、Debug Caller Exeがまだないため、初期化中に他の問題があるため、実行時にこれをまだテストできません。これが正しい方法であると確信しているため、投稿を回答としてマークします
解決
理由"& MyFrameGrabber :: HookFunction" BUF_HOOK_FUNCTION_PTRに変換できません。クラスのメンバーであるため、暗黙的に最初のパラメーターとして「this」があります。ポインター。したがって、メンバー関数を非メンバー関数に変換することはできません。2つの署名は同じように見えますが、実際には異なります。
インターフェイスを宣言し、呼び出す関数を定義し、クラスにそれを実装させ、コールバックの代わりにオブジェクト自体を渡します(インターフェイスは関数指向のオブジェクト指向の置換と考えることができます):
class IHookInterface{
public:
virtual long HookFunction(long, long, void*) = 0;
};
class HookClass : public IHookInterface{
public:
virtual long Hook(long, long, void*) {
// your code here...
}
};
//新しい定義: ThirdPartyGrab(...、IHookInterface、...);
編集-ライブラリを変更できない場合のその他の可能な解決策:静的関数ではなくシングルトンを使用します。
class HookClass{
public:
static HookClass& instance(){
static HookClass _instance;
return _instance;
}
long Hook(long, long, void*) {
// your code here...
}
};
long call_hook(long x,long y,void * z){
return HookClass::instance().Hook(x,y,z);
}
SECOND EDIT:初期化メソッドを使用してシングルトンクラスをわずかに変更し、適切なパラメーターでコンストラクターを呼び出すことができますが、次のソリューションよりもエレガントではない可能性があります。
class HookClass{
public:
HookClass(string x,string y...){
}
long Hook(long, long, void*) {
// your code here...
}
};
static HookClass * hook_instance = 0;
long call_hook(long x,long y,void * z){
if (0 != hook_instance){
return hook_instance->Hook(x,y,z);
}
}
int main(){
hook_instance = new HookClass("x","y");
ThirdPartyGrab(..., call_hook, ...);
}
他のヒント
プライベートメンバーメソッドには、暗黙的な this
ポインターが最初の引数としてあります。それを書き出すと、関数シグネチャが一致しないことは明らかです。
静的メンバー関数を記述する必要があります。これは、コールバック関数としてライブラリに渡すことができます。 HookFunction
の最後の引数である void *
は、Cookieに非常によく似ており、独自のポインタを渡すことができます。
つまり、全体として、次のようになります。
class MyClass { long MyCallback(long, long) { // implement your callback code here } static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) { return reinterpret_cast<MyClass*>(self)->MyCallback(a, b); } public: void StartGrab() { ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...); } };
もちろん、これは void *
引数が私が言ったことをしている場合にのみ機能します。 ThirdPartyGrab()
呼び出しでの this
の位置は、使用可能なパラメーター名を含む完全な関数シグネチャがある場合に簡単に見つけられるはずです。