\n |
[ トップページ ]
[ ____CommandPrompt ]
[ ____JScript ]
[ ____MySQL ]
[ ____Cygwin ]
[ ____Java ]
[ ____Emacs ]
[ ____Make ]
[ ____Perl ]
[ ____Python ]
[ ____OpenGL ]
[ ____C# ]
[ ____StyleSheet ]
[ ____C++ ]
[ ____Winsock ]
[ ____Thread ]
[ ____VisualStudio ]
[ ____C ]
[ ____Win32API ]
[ ____Lua ]
[ ____PhotoShop ]
ヘッダ検索
■ メンバー関数ポインタ
次のように展開するとわかりやすい
メンバ関数は通常の C スタイルの関数とはシグネーチャが異なる。
暗黙の this ポインタをもつ。
func : Foo::memberFunc() を指す Ptr なので, Foo に func() という FuncMem がなくても OK.
object->*func() === object->(*func)() === object->memberFunc()
C3837 :
FuncMem の アドレスを渡す場合は, &Foo::func; と明示する必要あり.
class Foo
{
public:
void func();
};
POINT
クラスのメンバ関数の型を typedef する。
関数ポインタ型の構文はわかりずらいので typedef で別名をつけると便利。
コンパイラに void T::( void ); 型を FuncPtr であると教える。
#typedef void ( T::*FuncPtr)();
{
// p はメンバ関数を指すためのポインタ変数。
FuncPtr p;
// メンバ関数ポインタにメンバ関数をセットする
p = T::func();
p = &T::func();
// コールするときは this に渡すインスタンスからよびだす。
class obj;
(obj.*p)();
WARNING
C スタイルの関数ポインタを必要とする場所で、 メンバ関数ポインタを渡すことはできない。
この場合は , 静的メンバ関数、または非メンバ関数を利用する。
シグナルハンドラ
#include< signal.h>
int main() {
// 静的メンバメソッドならば渡すことができる
signal( SIGINT, Test::signalHandler );
}
// グローバル変数経由でわたす インスタンスを取得して メンバ関数をよびだす
スタティックメンバ関数ならば 呼び出し規約は同じになるので
C スタイルの関数ポインタと互換性がある。
■ ステートパターン内で利用する
POINT
動作を表す変数( 動作もまた情報 ) -> ex. stateFunc ( 動作名をいれよう )
-> 応用例( FSM )
class obj
{
protected:
// 状態別 mem 関数の宣言:
typedef void (obj::*stateFunc)(); // objCls の funcPtr( 内部的には obj_stateFunc() )
// それを保持する変数
stateFunc statFn;
private:
// 状態別関数
void state1()
{
printf("do state1\n");
this->statFn = state2;
}
void state2()
{
printf("do state2\n");
this->statFn = state1; // cls 名を指定しなくても OK
}
public:
Obj(){
stateFunc() = state1;
}
// update 処理では状態関数を呼ぶだけ
inline void update(){
(this->*statFn)();
}
};
{
switch ( state ){
case STATE1: state1(); break;
case STATE2: state2(); break;
}
}
typedef void (T_Class::*SetParamProc)( const T_Param &val );
typedef const T_Param &(T_Class::*GetParamProc)();
// メンバ関数ポインタ を用いた todo 処理の例
class TestCls
{
/* TestCls の関数か, global関数かを cmp に通知 */
typedef void (TestCls::*Func)();
public:
// todo 一覧
void foo(){ printf("foo") };
void bar(){ printf("bar") };
TestCls(){
/* TestCls の foo() を渡すことを通知. ( & は任意 ) */
todoList.push_back( &TestCls::goo );
}
vector< Func > todoList;
void action(){
int i;
for( i=0; i< todoList.size(); i++ ){
Func p = todoList[i];
/* 呼ぶときは, どの inst かを通知 */
(this->*p)();
}
};
};
DESC
通常
typedef void (*func)();
cls
typedef void (clsName::*func)(); // void clsName::func() 型の funcPtr
関数 ptr の ads を渡すには ...
通常
void foo(){ ... }
func a = foo;
cls
typedef void (clsName::*func)(); // void clsName::func() 型の funcPtr
void clsName::bbb(){ ... }
関数 ptr を param とする function は
// template cls にすると, 関数の型を以下のように可変にできる
void setClassInfo( T_Class &inst,
SetParamProc set, GetParamProc get, std::string _name = "" );
template< class T_Class, class T_Param> // この cls の この param という
class Test : public TestValue< T_Param> {
private:
};
// 渡し方
// & をつける
POINT
template化 cls は cls 生成の時点で template 指定するが、
mem 関数 は 通常とおり使用できる.
関数ポインタに格納する関数は, [ class 名 ]も同一でなくてはならない。
派生先の関数でも格納は不可能( 派生先しかない情報にアクセスされたらOUT )
この場合は, virtual bcls::todoXXX(){} として枠組みをつくって,
派生先で 必要な処理を overwrite することで OK
もしくは, 各クラスで todo 処理をするふるまい [ actionTodo() ] を作成する
template ということは, class 名の部分を置換してやれば可能。
|
|
NINJAIDX 12