C++Builderで差し替えできるメンバ関数を作成する

C++Builderの拡張機能である__closureと__propertyを使うと、メンバ関数を実行時に他の関数と差し替えることができます。

処理の一部を他のクラスの処理に簡単に委譲することができます。

__closure

まず、__clocureの復習から。

C++Builderの__clocureは、メンバ関数のクラスが異なっていても引数と返値が同じであれば、同一型と見なします。

次の例では、異なるクラスTFooとTBarのメンバ関数を、変数funcに代入して実行しています。

//TFoo::FooとTBar::Barは引数と返値が同じ
struct TFoo {
  int Foo(int Arg) {
    return Arg * 2;
  }
};
struct TBar {
  int Bar(int Arg) {
    return Arg * 3;
  }
};

#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
  //関数の型を定義
  //引数にint型をひとつ取り、返値にint型を返す関数
  typedef int (__closure *PointerToAFunction)(int);
  PointerToAFunction func; //関数のポインタ

  //funcにTFoo::Fooを代入
  TFoo foo;
  func = foo.Foo;
  std::cout << func(3) << std::endl; //=> 6

  //funcにTBar::Barを代入
  TBar bar;
  func = bar.Bar;
  std::cout << func(3) << std::endl; //=> 9

  return 0;
}

メンバ関数をプロパティにする

VCLでよく見かけるのが、次のようなコード。

class TBaz {
public:
  TBaz() : FOnFunc(NULL) {}

  //関数の型を定義
  //引数にint型をひとつ取り、返値にint型を返す関数
  typedef int (__closure *PointerToAFunction)(int);

  //代入できるメンバ関数をプロパティに
  __property PointerToAFunction OnFunc = { read=FOnFunc, write=FOnFunc };

  //FOnFuncが設定されているときは、設定された関数を使用する
  int Func(int Arg) {
    if (FOnFunc) {
      return FOnFunc(Arg);
    }
    return 0;
  }
private:
  //関数ポインタ
  PointerToAFunction FOnFunc;
};

このようにすると、処理の一部を他のクラスのメンバ関数に委譲することができます。

VCLのボタンのクリックイベントのコードをフォームのメンバ関数に書けるもこの仕組みのおかげですね。

使用例は次のようになります。

struct TFoo {
  int Foo(int Arg) {
    return Arg * 2;
  }
};
struct TBar {
  int Bar(int Arg) {
    return Arg * 3;
  }
};

#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
  TBaz baz;
  std::cout << baz.Func(3) << std::endl; //=>0

  //TBaz::OnFuncにTFoo::Fooを割り当てる
  TFoo foo;
  baz.OnFunc = foo.Foo;
  std::cout << baz.Func(3) << std::endl; //=>6(TFoo::Fooが使用される)

  //TBaz::OnFuncにTBar::Barを割り当てる
  TBar bar;
  baz.OnFunc = bar.Bar;
  std::cout << baz.Func(3) << std::endl; //=>9(TBar::Barが使用される)

  return 0;
}

参考になるページ

コメント

  1. Pingback: 山本隆の開発日誌

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です