C++の基礎 - コールバック関数

提供:MochiuWiki : SUSE, EC, PCB
2021年11月18日 (木) 15:10時点におけるWiki (トーク | 投稿記録)による版 (文字列「<source」を「<syntaxhighlight」に置換)
ナビゲーションに移動 検索に移動

コールバック関数とは

コールバックとは、プログラミングにおいて、他のコードの引数として渡されるサブルーチンである。
これにより、低レベルの抽象化層が高レベルの層で定義された関数(サブルーチン)を呼び出せるようになる。

C言語のサンプルコード

下記のサンプルコードにおいて、main() -> Hello() -> Show() の順番に呼ばれる機構をコールバックと呼ぶ。

<syntaxhighlight lang="c++">
// main.c
#include <stdio.h>

void Hello(void (fnShow)(void));
void Show(void);

int main()
{
   Hello(Show);
   return 0;
}

void Hello(void (fnShow)(void))
{
   fnShow();
}

void Show(void)
{
   printf("Hello World!!");
}
</source>



C++言語のサンプルコード

下記のサンプルコードにおいて、CInvoker::Executeを呼び出すことでCInvoker::CallbackFuncがコールバックされる。

<syntaxhighlight lang="c++">
// CInvoker.h
class CInvoker
{
   private:
      int m_Data;
 
   pubic:
      CInvoker();
      ~CInvoker();
      void Execute();
      static int CallbackFunc(void* userData); // コールバック関数
}

// CInvoker.cpp
// コンストラクタ
CInvoker::CInvoker() : m_Data(100)
{
}

// デストラクタ
CInvoker::~CInvoker()
{
}
void CInvoker::Execute()
{
   int result = 0;
   result = reinterpret_cast<CInvoker*>(this)->CallbackFunc(this);
}
 
// コールバック関数
int CInvoker::CallbackFunc(void* clsObject)
{
   CInvoker clsInvoker = reinterpret_cast<CInvoker*>(clsObject);

   return clsInvoker->m_Data;
}
</source>



仕組み

C++のクラスでコールバックメソッドを実行するには静的(static)なメソッドにしなければならない。
静的(static)でないと、以下のコンパイルエラーが表示される。

仮想関数のアドレスを取ろうとしました

これは、クラスが生成されるまでメモリ上に展開されず、呼び出し元のメソッドがどのポインタを参照すればよいかわからないためエラーになる。
即ち、静的メソッドにしてポインタの位置を固定した後、reinterpret_castでアドレスの解釈を強制的に変更することで、
動的に取得したクラスメソッドにアクセスできるようになる。