id:banderさんところで知って面白そうなので実験してみた。
baseを超えてアクセスできるともっと便利なんだけどなぁ。


むりやりキャストしたら関係ないクラスの関数でもいけそうです。
すげーーーーー!マジこれは革命ですよ。


staticメンバ関数にして内部でわざわざポインタ受け取ってアロー演算子を使ってメンバにアクセスするのはもう古い!はず!


無名unionを使って普通の関数も登録できるようにした。
で、ここで気が付いたのだが、登録したthisポインタとクラス関数の型に関連が無いと、
Callbackを呼んでいるところでコンパイルエラーになることが判明。
なのでfuncbaseで適当にクラス関数型を作ってもしてもだめだった。。


でも一応普通の関数も呼べるしまぁいいかな。全員base派生しとけっていう話です。


もしかしたら無理やりキャストにより呼び出すことはできるかも。
と思って試したら出来た。

  • BCB

BCBだと駄目だ!メンバ関数のアドレスをキャストできねぇ!
使えねぇ〜。


諦めてboost::bindとboost::functionを使ったほうがよさそうかな。

#include "stdafx.h"
#include
#include
#include
using namespace std;

class base
{
public:
  base(){;}
  virtual ~base(){;}
};

class funcbase
{
public:
  funcbase(){;}
  virtual ~funcbase(){;}
};

class A : public base
{
private:
  int a;
public:
  A() { a = 0; }
  A(int i) { a = i; }
  virtual ~A() { a = 0; }
public:
  void funcA(void) { cout << "funcA! = " << a << endl; }
};

class B : public base
{
private:
  int b;
public:
  B() { b = 10; }
  B(int i) { b = i; }
  virtual ~B() { b = 0; }
public:
  void funcB(void) { cout << "funcB! = " << b << endl; }
};

typedef void (*FUNCTION)(void);
typedef void (funcbase::*CLASS_FUNCTION)(void);

class CallbackHolder
{
private:
  base *ptr;

  union
  {
    void *address;
    CLASS_FUNCTION cfn;
    FUNCTION fn;
  };

public:
  CallbackHolder()
  {
    ptr = NULL;
    address = NULL;
  }

  CallbackHolder(base *p, CLASS_FUNCTION f )
  {
    Set(p,f);
  }

  CallbackHolder( FUNCTION f )
  {
    Set(f);
  }

  ~CallbackHolder(){}
  
  CallbackHolder &Set( base *p, CLASS_FUNCTION f )
  {
    ptr = p;
    cfn = f;
    return (*this);
  }

  CallbackHolder &Set( FUNCTION f )
  {
    ptr = NULL;
    fn = f;
    return (*this);
  }
  
  void Callback(void)
  {
    if ( address == NULL ) return;

    if ( ptr )
      (((funcbase *)ptr)->*cfn)();
    else  
      fn();
  }
};

typedef vector CallbackArray;
typedef vector BaseArray;

void test(void)
{
  cout << "test" << endl;
}

int main(int argc, char* argv[])
{
  CallbackHolder cb;
  CallbackArray cbs;
  BaseArray bases;

  bases.push_back(new A());
  bases.push_back(new A());
  bases.push_back(new B());
  bases.push_back(new B());

  // クラスのメンバ関数を登録.  
  cbs.push_back( cb.Set( bases[0], (CLASS_FUNCTION)A::funcA ) );
  cbs.push_back( cb.Set( bases[1], (CLASS_FUNCTION)A::funcA ) );
  cbs.push_back( cb.Set( bases[2], (CLASS_FUNCTION)B::funcB ) );
  cbs.push_back( cb.Set( bases[3], (CLASS_FUNCTION)B::funcB ) );
  // 普通の関数も登録.
  cbs.push_back( cb.Set( test ) );

  // コールバック呼び出す.
  for ( int i = 0 ; i < cbs.size() ; i++ )
  {
    cbs[i].Callback();
  }

  for ( i = 0 ; i < bases.size() ; i++ )
  {
    delete bases[i];
  }

  bases.clear();  
  getch();
  return 0;
}

コールバックできた!

funcA! = 0
funcA! = 0
funcB! = 10
funcB! = 10
test