2014-06-17 追記 2014-06-13 新規 [C++] メンバー関数の関数ポインター ======================================================================== (MinGW gcc (GCC) 4.5.4) クラスのメンバー関数への関数ポインターの定義と使用。 □ funcpointer.cpp --- #include <iostream> using namespace std; class A { private: static int staticdata; int data; public: A(int data) : data(data) { } static int staticfunc(int data) { return data - staticdata; } int func(int data2) { return data + data2; } }; int A::staticdata = 777; int main() { A a(111); cout << "staticfunc(): " << A::staticfunc(999) << endl; cout << "func(): " << a.func(222) << endl; cout << " 関数ポインター " << endl; int (*sfp)(int data) = A::staticfunc; // (1) static 関数ポインター cout << "staticfunc(): " << sfp(888) << endl; // (2) int (A::*fp)(int data2) = &A::func; // (3) インスタンス関数のポ インター cout << "func(): " << (a.*fp)(333) << endl; // (4) return 0; } --- □ 実行結果 --- staticfunc(): 222 func(): 333 関数ポインター staticfunc(): 111 func(): 444 --- (1) static 関数ポインターの定義と初期化 int (*sfp)(int data) = A::staticfunc; 通常のグローバル関数の関数ポインターと同じように定義する。 関数ポインターは、 クラス名 :: 関数名 という形で取得する。 定義部分には、クラス名の要素が入っていないので、他のクラスでも同じシグネ チャーの関数なら、この関数ポインターを使うことができる。 たとえば、B クラスに同じシグネチャーの static int staticfunc(int data) があれば、 sfp = B::staticfunc; として、関数ポインターを設定できる。 (2) static 関数ポインターの利用 cout << "staticfunc(): " << sfp(888) << endl; 通常のグローバル関数の関数ポインターと同じように利用すればよい。 (3) インスタンス関数ポインターの定義と初期化 関数ポインター名の前に、「A::」をつけておく。 int (A::*fp)(int data2) = &A::func; スコープ解決しないと、つぎのコンパイルエラーが出る。 cannot convert 'int (A::*)(int)' to 'int (*)(int)' in initialization 関数ポインターは、 & クラス名 :: 関数名 という形で取得する。「&」がないとコンパイルエラーになる。 invalid use of non-static member function 'int A::func(int)' (4) インスタンス関数ポインターの利用 cout << "func(): " << (a.*fp)(333) << endl; インスタンス a を使う。したがって、少し、違和感はあるが、次のような形で 利用する。 (インスタンス名 .* 関数ポインター名)(引数のリスト) インスタンスがないと使えないので、 fp(333) では、つぎのコンパイルエラーが出る。 must use '.*' or '->*' to call pointer-to-member function in 'fp (...)', e.g. '(... ->* fp) (...)' もちろん、クラス A のメンバー関数用なので、まったく同じシグネチャーを持 つ別のクラスのメンバー関数のインスタンスで使おうとしても、コンパイルエ ラー。 B b; (b.*fp)(333) では、つぎのエラー。 pointer to member type 'int (A::)(int)' incompatible with object type 'B' ■ メンバー関数ポインターのポリモーフィズム (2014-06-17 追記) 上記 A クラスを継承した D クラスをつきのように定義する。 --- class D : public A { public: D(int data) : A(data) { } int func(int data) { return data * 2; } }; --- このメンバー関数 func() は、基底クラス A のメンバー関数 func() をオー バーライドしている。 この D クラスのインスタンスを基底クラス A 型として扱う。 つぎのようなコードを上にサンプルに追加する。 --- A* d = new D(11); // (5) fp = static_cast<int (A::*)(int)> (&D::func); // (6) cout << "func(): " << (d->*fp)(333) << endl; // (7) --- この部分の実行結果としては、つぎのようになる。 --- func(): 666 --- A クラスの型だが、D クラスのメンバー関数 func() を実行しているのが確認で きる。 (5) A クラスの型として、D クラスのインスタンスを生成する。 A* d = new D(11); // (5) (6) D クラスのオーバーライドしているメンバー関数 func を、A クラスの関数 ポインターに代入する fp = static_cast<int (A::*)(int)> (&D::func); // (6) このとき、アップキャストすることになるが、不思議なことに、static_cast が 必要。 (7) D クラスのインスタンスを使って、この関数ポインターが指す関数を実行す る cout << "func(): " << (d->*fp)(333) << endl; // (7) インスタンスのポインター d を使う。したがって、少し、違和感はあるが、次 のような形で利用する。 (インスタンスのポインター名 ->* 関数ポインター名)(引数のリスト) 以上 --- 2014-06-17 追記 メンバー関数のポリモーフェィズム ---
最新の画像[もっと見る]
-
あけましておめでとうございます 11年前
-
今年もよろしくお願いいたします 12年前
-
あけましておめでとうございます 13年前
-
あけましておめでとうございます 16年前
※コメント投稿者のブログIDはブログ作成者のみに通知されます