2014-06-20 新規 [C++] メンバー関数の関数ポインターをメンバー変数にする ====================================================================== (MinGW gcc (GCC) 4.5.4) クラスのメンバー関数への関数ポインターの定義と使用。 □ funcpointer.cpp --- #include <iostream> using namespace std; class A { private: int data; int (A::*fp[2])(int data); // (1) インスタンス関数のポインター public: A(int data) : data(data), fp({&A::func, &A::func2}) { // (2) } int exec(int index, int data) { return (this->*fp[index])(data); // (3) } private: int func(int data) { return this->data + data; } int func2(int data) { return this->data - data; } }; int main() { A a(100); cout << "0: " << a.exec(0, 10) << endl; // (4) cout << "1: " << a.exec(1, 20) << endl; return 0; } --- □ 実行結果 --- 0: 110 1: 80 --- (1) インスタンス関数ポインターの配列 通常のメンバー関数ポインターの配列と同じ。 int (A::*fp[2])(int data); // (1) インスタンス関数のポインター (2) インスタンス関数ポインターの配列の初期値 A(int data) : data(data), fp({&A::func, &A::func2}) { // (2) } コンストラクターの初期化リストで、 fp({&A::func, &A::func2}) ということはできないかと思ったが、どうやらできる。 ただし、つぎの警告が出る。 extended initializer lists only available with -std=c++0x or -std=gn u++0x コンパイルするときに上記のオプションを指定すれば、警告は出なくなる。 (3) 関数ポインターの配列を実行するメンバー関数 return (this->*fp[index])(data); // (3) this ポインターを使わないといけない。使わずに、 (fp[index])(data) とすると、つぎのコンパイルエラー。 must use '.*' or '->*' to call pointer-to-member function in '((A*)this)->A::fp[index] (...)', e.g. '(... ->* ((A*)this)->A::fp[index]) (...)' メンバー関数のポインターは、".*" か "->*" を使わないといけないからかな。 (4) 実行 たんに、メンバー関数を呼んでいるだけ。最初の引数はメンバー関数のポイン ターの配列の添字を指定している。 cout << "func(): " << a.exec(0, 10) << endl; // (4) メンバー関数のポインターの配列 fp を public にして、main() 関数でつぎの ように使おうとしても、 (a.*fp[0])(30) コンパイルエラー。 'fp' was not declared in this scope まあ、上記の書き方だと、main 関数の中で fp を定義しないとだめだ。 以上
2014-06-19 新規 [C++] 関数テンプレートのポインター ======================================================================== (MinGW gcc (GCC) 4.5.4) □ functionpointer_template.cpp --- #include <iostream> using namespace std; template<class T> // (1) T square(T a) { return a * a; } template<class T, class F> // (2) T calc(T a, F func){ return func(a); } int main() { int (*p)(int) = square; // (3) この使い方はあまり意味ない感じ cout << p(2) << endl; // (4) cout << p(3.4) << endl; // (5) cout << calc(2, square<int>) << endl; // (6) cout << calc(3.4, square<double>) << endl; // (7) // cout << calc(5, square) << endl; // コンパイルエラー return 0; } --- □ 実行結果 --- 4 9 4 11.56 --- (1) 関数テンプレートの宣言 (2) 関数テンプレートのポインターを引数に持つ関数テンプレートの宣言 (3) 関数テンプレートを実体化したものを関数ポインターに設定 関数ポインターは、通常の関数ポインターと変わりはない。テンプレートの型は 自分で設定している。 int (*p)(int) = square; // (3) この使い方はあまり意味ない感じ (4)(5) 関数ポインターの利用 int 型の引数を取るので、そのまま使う。 cout << p(2) << endl; // (4) int 型の引数を取るので、double 型の引数を渡しても、int 型として処理され る。 cout << p(3.4) << endl; // (5) (6)(7) 関数テンプレートのポインターを引数に持つ関数テンプレートの利用 int 型を明示しているの、int 型の引数の square 関数ポインターを渡す。 cout << calc(2, square<int>) << endl; // (6) double 型を明示しているの、double 型の引数の square 関数ポインターを渡す。 cout << calc(3.4, square<double>) << endl; // (7) つぎのように、データ型を明示していないと、コンパイルエラーになる。 calc(5, square) no matching function for call to 'calc(int, <unresolved overloaded function type>)' 以上
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 追記 メンバー関数のポリモーフェィズム ---