
おりばーです。
今年に入ってC/C++で開発することが多く、C#ではdelegate
で一発だったコールバック関数をC++で使うのも一苦労したのでメモ書きです。
コールバック関数とは
普段何気なく使っているコールバック関数ですが、定義というか他人に説明するときにどうやって説明するか悩んでしまったので調べました。
コールバック(英: Callback)とは、プログラミングにおいて、他のコードの引数として渡されるサブルーチンである。これにより、低レベルの抽象化層が高レベルの層で定義されたサブルーチン(または関数)を呼び出せるようになる。
コールバック – Wikipedia
コード(疑似C言語)で表すと
// お辞儀をする = サブルーチン void bow(void) { printf("Hello! How are you doing?"); } // 挨拶 void hello(void (bowFunc)(void)) { bowFunc(); } int main() { hello(bow); return 0; }
のようmain()
-> hello()
-> bow()
の順番に呼ばれる機構をコールバックと呼ぶらしいです。
C++でコールバック関数
ここから本題です。まどろっこしい説明はあとでいきなりコードです。
ソースコード
Invoker.h
class Invoker { private: int dummyData_; pubic: Invoker(); ~Invoker(); // コールバック関数 static int CallbackFunc(void* userData); // 呼び出し元 void Execute(); }
Invoker.cpp
// コンストラクタ Invoker::Invoker() : dummyData_(100) { } // デストラクタ Invoker::~Invoker() { } // コールバック実態 int Invoker::CallbackFunc(void* userData)) { Invoker invokerObject = reinterpret_cast<Invoker*>(userData); // 100が返る return invokerObject->dummyData_; } // 実行関数 void Invoker::Execute() { int result = 0; result = reinterpret_cast<Invoker*>(this)->CallbackFunc(this); }
これでInvoker::Execute
を呼び出すことでInvoker::CallbackFunc
がコールバックされます。
仕組み
クラス内のコールバックでミソになるのはstatic
で、staticなしだと
仮想関数のアドレスを取ろうとしました
といったエラーが(Visual Studioだと)吐き出されると思います。
これは、クラスがnew
されるまでメモリ上に展開されず、呼び出し元の関数がどのポインタに参照すればよいかわからないため出力されるエラーです。すなわちstatic
で静的関数にしてポインタの位置を固定してあげてreinterpret_cast
でアドレスの解釈を強制的に変更してあげることで動的取得したクラス関数にアクセスできるようになるわけです。
たまにやり方を忘れるのでメモ書きでした。