「C++の基礎 - コールバック関数」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(Wiki がページ「コールバック関数の実装(C/C++)」を「C++の基礎 - コールバック関数」に、リダイレクトを残さずに移動しました)
(文字列「<source」を「<syntaxhighlight」に置換)
5行目: 5行目:
== C言語のサンプルコード ==
== C言語のサンプルコード ==
下記のサンプルコードにおいて、main() -> Hello() -> Show() の順番に呼ばれる機構をコールバックと呼ぶ。<br>
下記のサンプルコードにおいて、main() -> Hello() -> Show() の順番に呼ばれる機構をコールバックと呼ぶ。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // main.c
  // main.c
  #include <stdio.h>
  #include <stdio.h>
32行目: 32行目:
== C++言語のサンプルコード ==
== C++言語のサンプルコード ==
下記のサンプルコードにおいて、CInvoker::Executeを呼び出すことでCInvoker::CallbackFuncがコールバックされる。<br>
下記のサンプルコードにおいて、CInvoker::Executeを呼び出すことでCInvoker::CallbackFuncがコールバックされる。<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // CInvoker.h
  // CInvoker.h
  class CInvoker
  class CInvoker

2021年11月18日 (木) 15:10時点における版

コールバック関数とは

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

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でアドレスの解釈を強制的に変更することで、
動的に取得したクラスメソッドにアクセスできるようになる。