C++/CLIでのクラスのメンバ関数の関数テーブル作成
メンバ関数をテーブル化して呼び出そうと思い、色々やってみたが一筋縄ではいかなかった。
ref class Form {
int func_0( void );
int func_1( void );
}
というシグネチャの関数をテーブル化しようとして、まずは
Cの関数テーブル作成の要領で、確実に駄目だろうと思いつつも
array<int (*func[])(void)> ^func_tbl;
としてみる。見るからにダメだろ、常識的に考えて…という予想どおり、アウト。
しかし、
typedef int (*MethodPointer)(void);
と、一旦関数ポインタをMethodPointerという名前にしておき、
array<MethodPointer> ^func_tbl;
func_tbl = gcnew array<MethodPointer>(2);
とするとコンパイルは通る。
しかし、クラス外の MethodPointer型の関数を登録する分には問題は生じず、
普通に関数ポインタテーブルとしての人生を謳歌できるのだが、
MethodPointer型のメンバ関数を登録しようとするとコンパイラに怒られる。
こんな感じで。
NameSpace::Form::Func': 関数呼び出しには引数リストがありません。
メンバへのポインタを作成するために '&NameSpace::Form::Func' を使用してください
※NameSpaceは大元のネームスペースです。
なので、コンパイラの言われるまま、&NameSpace::Form::Func をセットしてやろうと思いやってみると
delegate インスタンスを作成する場合以外に、'NameSpace::Form::Func' のアドレスを指定できません
という追い討ちをかけられる事になる。
結局のところ、メンバ関数ポインタを保持したいんだったらデリゲートを使ってね、という事のよう。
デリゲートは複数の関数を登録でき、Invoke()で一括処理できるので便利!とも思ったが、
登録してある関数を指定して実行とか、途中で条件分岐で処理を止めるとかは別のお話といった
感じなので、結局はデリゲートの配列を持つことに…。
最終的にはこんな感じ。
delegate int FuncIntVoid( void ); // クラスの外での宣言
// クラス宣言
ref class Form {
array<FuncIntVoid^> ^m_FuncTbl;
int Func_0( void );
int Func_1( void );
};
// テーブル作成
m_FuncTbl = gcnew array<FuncIntVoid^>{
gcnew FuncIntVoid( this, &Form::Func_0 ),
gcnew FuncIntVoid( this, &Form::Func_1 ),
}
// 実行
for( int i = 0; i < m_FuncTbl->Length; i++ ) {
m_FuncTbl[i]->Invoke();
}
こんな感じでイケる。
注意が必要なのは、メンバ関数の登録の際には第1引数に送り元となるthisを
指定しなければならないということ。メンバ関数ではなく、どっかのグローバル関数を
登録したりするときは必要ない。
…という感じで実装してみたが、なんかスマートじゃない気が…。
もっと他にやり方あるんじゃないかな。
日付とか時間の管理とか
VBだとDate型の環境が非常に整っており、比較的簡単に日付の操作とかができるのだが、
C++/CLIにはないのかね?という事で自作してみた。
※.NET FrameworkクラスライブラリにSystem::DateTime構造体ってのがあって、
これを使えばいいんじゃないかという話も…。
ただ、使うにしてもマネージクラスにしか使えないので、アンマネージオブジェクト内で
使うにはやはり自作なのか…。
time_t型、tm構造体を主として使う。
time_t型は時間の保持として使い、tm構造体はtime_t型に時間をセットするのに使う。
tm構造体の各メンバ(年、月、日、etc...)に値をセットし、
mktime()でセットする感じだ。
time_t -> tm への変換は localtime() を使って行う。
gmtime() を使ったせいで、世界協定時刻を取得し、毎回9時間の時差に悩まされたというのは内緒だ…。
とりあえず、時間の加減算、取得、セットなどができるクラスを作っている最中。
最終更新:2008年11月14日 13:36