クラス内での関数ポインタの配列を作る

[戻る]
たかお 2007/07/07(土) 17:37:40
こんにちわ。たかおと申します。VC++6で作成してます。
現在ファイル処理関連のクラスを作成しています。
扱うファイルの種類が複数(20種類ぐらい)ある為、
それに応じた処理をクラスのメンバ関数として作成しました。

Class CFileProc
{
public:
  CFileProc();
  ~CFileProc();

 int SaveProc(const char *FileName, Index);
 int LoadProc(const char *FileName, Index);

private:

 int (*Save_Func[20])(CFile*);      // セーブ用関数ポインタ
  int (*Load_Func[20])(const char*); // ロード用関数ポインタ

  int Save_1(CFile*);  // 各ファイルに対応した処理関数(保存用)
      〜
  int Save_20(CFile*);

  int Load_1(const char*); // 各ファイルに対応した処理関数(読出用)
      〜
  int Load_20(const char*);

};

呼び出し元はSaveProc()(又はLoadProc())に対象のファイル名と
ファイルの種類を示すIndexだけを渡して後はクラスの中で勝手に
処理させようと思っています。
そして、SaveProc()(又はLoadProc())の中の処理でIndex毎に
switch文やif文で分岐をさせたくないので、関数ポインタの配列で
処理してしまえば楽なのかな?と思い作業を始めた次第です。

問題は関数ポインタの取得の方法でして・・・、このクラスのコンストラクタで
*Save_Func(or *Load_Func)にそれぞれのメンバ関数を割り当て(?)たいの
ですが、記述方法がわかりません。

単純に
「pSaveFunc[0] = Save_1;」としたところ、以下のエラーが出ました。
----------------------------------------------------------------------
error C2440: '=' : 'int (__thiscall CFileMakeEdit::*)(class CFile *)' から
 'int (__cdecl *)(class CFile *)' に変換することはできません。
----------------------------------------------------------------------
型が違うと言うと言われているとは思うのですが、内容が良く理解出来ません。
コンストラクタでの定義の仕方を教えてください。
またそもそも、関数ポインタも今まで使った事が無く学習がてらやっている為、
セオリーとして今回の様な使い方が正しい(出来る)のかも良く解っていません。
私の様な使い方は如何なものなのでしょうか?

以上宜しくお願い致します。

たかお 2007/07/07(土) 17:46:25
エラー表示の
---------------------------------------------------------------------------
error C2440: '=' : 'int (__thiscall CFileMakeEdit::*)(class CFile *)' から
---------------------------------------------------------------------------
は
---------------------------------------------------------------------------
error C2440: '=' : 'int (__thiscall CFileProc::*)(class CFile *)' から
---------------------------------------------------------------------------
ですね。すみません。

wclrp ( 'o') [HomePage] 2007/07/07(土) 18:16:10
メンバ関数はC言語のときのような関数へのポインタと互換性ありません。

以下はメンバ関数ではない関数へのポインタだね。
int (*Save_Func[20])(CFile*);

以下はメンバ関数だね。
Class CFileProc { int Save_1(CFile*); 〜略〜


もし、以下のメンバ関数が自分のメンバ変数を一切使わないなら
Class CFileProc {
  static int Save_1(CFile*);
      〜
  static int Save_20(CFile*);

  static int Load_1(const char*);
      〜
  static int Load_20(const char*);
staticを付ければコンパイルできるはず。

wclrp ( 'o') [HomePage] 2007/07/07(土) 18:22:29
CFileProc::Save_1などからCFileProcのメンバ変数やメンバ関数を利用したいなら
staticを付けつちゃだめ。

以下を関数へのポインタではなくメンバ関数へのポインタに変える必要がある。
int (*Save_Func[20])(CFile*);
int (*Load_Func[20])(const char*);

メンバ関数へのポインタは関数へのポインタと比べるとちょっと難しい。
詳しいことは検索したり本読んだりしてくれ。

全容がわからないが
可能ならデータの種類をクラスにしたいところだな。
説明が長くてつらくなるのでやめとく。

Blue 2007/07/07(土) 18:38:38
とりあえずtypedefを使ってもいいなら

class Foo
{
public:
    Foo()
    {
        func[0] = funcA;
        func[1] = funcB;
    }

    typedef (Foo::*FUNC)(int);
    FUNC func[2];

    int funcA(int){return 1;}
    int funcB(int){return 2;}
};

int main()
{
    Foo f;
    
    int n = (f.*(f.func[0]))(0);

    return 0;
}

てな感じです。

Blue 2007/07/07(土) 18:43:39
typedefを使わない場合は

int (Foo::*func[2])(int);

です。

つまり
> int (*Save_Func[20])(CFile*);      // セーブ用関数ポインタ
は
 int (CFileProc::*Save_Func[20])(CFile*);      // セーブ用関数ポインタ
です。

呼び出し側は、インスタンスが必要になるので
>int n = (f.*(f.func[0]))(0);
というようになってしまうのです。
(*(f.func[0])はたんなる関数ポインタしかとれないため。)

たかお 2007/07/07(土) 20:58:11
[[解決]]
皆さんありがとうございます。
順番に・・・。

>以下はメンバ関数ではない関数へのポインタだね。
>int (*Save_Func[20])(CFile*);
関数ポインタにも、対応する対象があると言う事でしょうか?
*Save_Func[]()もクラス内で定義しているから、
メンバ関数も簡単にセット出来ると思ってました。

>もし、以下のメンバ関数が自分のメンバ変数を一切使わないなら
>staticを付ければコンパイルできるはず。
メンバ変数or他のメンバ関数は使う予定はありません。
が、万が一使いたくなった場合は、別途面倒臭い事をしないと
ならないって事ですね。

>とりあえずtypedefを使ってもいいなら
取り合えずそのあたりは制約はありませんので
動作すれば自由なのですが・・・、

>class Foo
このクラスを私の作ったCFileProcに置き換えてみれば
良いという事ですよね?

>typedef (Foo::*FUNC)(int);
この宣言の時点で?でした(^^;

以下のサイトにちょっとした解説がありましたが・・・
http://hp.vector.co.jp/authors/VA018041/programming/cpp/14.html
typedefにこんな使い方があったんですね・・・。

>呼び出し側は、インスタンスが必要になるので
>>int n = (f.*(f.func[0]))(0);
>というようになってしまうのです。
>(*(f.func[0])はたんなる関数ポインタしかとれないため。)

この部分だけがちょっと理解出来ません(^^;
関数ポインタとはなんぞや?と言うのをもうちょっと
勉強しないと駄目ですね・・・。
簡単に速く(?)関数にアクセスする為の手法〜ぐらいの認識でしか
なかったもので・・・。

職場で作業しており自宅に帰ってきてしまった為、
すぐには試せませんので週明けにも実行してみたいと思います。
ひとまず解決ということで・・・ありがとうございました!!

Blue 2007/07/08(日) 02:56:20
参考サイトです。
>http://www7b.biglobe.ne.jp/~robe/cpphtml/html03/cpp03057.html

そこの一番最後にもあるように
>this->* は省略できない
ということで、ちょっと面倒な書き方になってしまうのです。

だったらいっそのことインデックスを渡して関数ポインタの配列を実行する
ようなメソッドをつくるとか。

class Foo
{
public:
    int func(int n, int m)
    {
        static int (Foo::*f[2])(int) = { funcA, funcB };
        return (this->*f[n])(m);
    }
    int funcA(int){return 1;}
    int funcB(int){return 2;}
};

int main()
{
    Foo foo;
    int n = foo.func(0, 0); // n = 1
    return 0;
}

古いスレッドには追加発言できません。