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;
}
Pingback: 山本隆の開発日誌