C++言語解説:3-1:関数ポインタ
2002-08-25 |
[C++ Index Top] [Prev] [Next] |
[概要] 今まで何気なく使ってきた「関数名」について改めて考えてみます。実は関数名 もポインタなのです。 [構成]・関数ポインタ * 関数名の考え方 * オーバーロード関数へのポインタ ●関数ポインタ ◆関数名の考え方 ・今まで不思議に感じたことは無いでしょうか。関数を定義した後、関数名を記述す るだけで実行できること。プロトタイプ宣言をすれば定義部は後回しに出来ること。 純粋仮想関数を定義するには「関数名 = 0;」であったこと。 ・特に純粋仮想関数の定義で「おや?」と思う方が多くなるようです。実は関数名も ポインタなのです。あまりによく使用する機能であるため、簡略化された記述方式 が採用されており、これが逆に理解の妨げになっています。 ・まずはじめに関数へのポインタを見ることにします。 [List1.関数ポインタの例] ┌───────────────────────────────────┐ #include <iostream> using namespace std; void message1(); void message2(); int main() { void (*p_func)(); //関数ポインタの定義 int i_select; cout << "1:Message1, 2:Message2 : "; cin >> i_select; if (i_select == 1) p_func = &message1; //message1() else p_func = &message2; //message2() (*p_func)(); //関数実行(形式その1) if (i_select == 1) p_func = &message2; //message2() else p_func = &message1; //message1() p_func(); //関数実行(形式その2) return 0; } void message1() { cout << "MESSAGE1" << endl; return; } void message2() { cout << "MESSAGE2" << endl; return; } └───────────────────────────────────┘ ┌───────────────────────────────────┐ [出力結果] 1:Message1, 2:Message2 : 1 MESSAGE1 MESSAGE2 └───────────────────────────────────┘ ・List1にある void (*p_func)(); が関数ポインタの宣言です。void戻値の引数無し型関数へのポインタを宣言してい ます。 ・引数や戻り値があるタイプの関数ポインタを宣言する場合は ┌───────────────────────────────────┐ double (*p_func)(int, double); 戻値型 引数型リスト └───────────────────────────────────┘ のように記述します。 ・関数のアドレス取得は、通常のオブジェクトを扱う場合と同様で p_func = &message1; のように&演算子を使用します。 ・ポインタを介した関数の実行は (*p_func)(); として行います。*演算子により、ポインタの指すアドレスを参照させています。そ して後ろの()は引数です。今回は引数無し関数を扱っているので、()のみです。 ・そしてもう一つ p_func(); まるで関数名のように記述することも可能です。ここである実験をしてみます。 [List2.関数ポインタの例--ポインタ形式記述] ┌───────────────────────────────────┐ #include <iostream> using namespace std; void message1(); void message2(); int main() { int i_select; cout << "1:Message1, 2:Message2 : "; cin >> i_select; if (i_select == 1) message1(); //message1() else message2(); //message2() if (i_select == 1) (*message2)(); //message2ポインタ記述 else (*message1)(); //message1ポインタ記述 return 0; } void message1() { cout << "MESSAGE1" << endl; return; } void message2() { cout << "MESSAGE2" << endl; return; } └───────────────────────────────────┘ ┌───────────────────────────────────┐ [出力結果] 1:Message1, 2:Message2 : 1 MESSAGE1 MESSAGE2 └───────────────────────────────────┘ ・そうです。いきなり関数ポインタ記述ができてしまいました。これでわかったと思 いますが、関数名は式中で利用される場合、自動的に関数へのポインタへ変換され ているのです。 ・この処理の仕方は「配列名」に似ています。恐らく同じ処理系統にするため、この ような方法が取られたと思うのですが、逆に混乱を招いている気がします。 ◆オーバーロード関数へのポインタ ・オーバーロード関数へのアドレスを取得する場合、関数ポインタについてもそれぞ れの型を用意します。 ・例えば int CalFunc(int i_a); int CalFunc(int i_a, int i_b); へ適用する関数ポインタは int (*p_func1)(int); int (*p_func2)(int, int); となります。 ・アドレスの代入は今までと同様に&演算子を用います。この際、ポインタの型定義に 沿ったオーバーロード関数が適用されます。 p_func1 = &CalFunc; //CalFunc(int) p_func2 = &CalFunc; //CalFunc(int, int) ・それでは、List3にオーバーロード関数ポインタの例を示します。 [List3.オーバーロード関数へのポインタ] ┌───────────────────────────────────┐ #include <iostream> using namespace std; int CalFunc(int i_a); int CalFunc(int i_a, int i_b); int main() { int (*p_func1)(int); int (*p_func2)(int, int); p_func1 = &CalFunc; //CalFunc(int) p_func2 = &CalFunc; //CalFunc(int, int) cout << (*p_func1)(10) << endl; cout << (*p_func2)(10, 20) << endl; return 0; } int CalFunc(int i_a) { int tmp; tmp = 2 * i_a; return tmp; } int CalFunc(int i_a, int i_b) { int tmp; tmp = 2 * (i_a + i_b); return tmp; } └───────────────────────────────────┘ ┌───────────────────────────────────┐ [出力結果] 20 60 └───────────────────────────────────┘ [Revision Table] |Revision |Date |Comments |----------|-----------|----------------------------------------------------- |1.00 |2002-08-25 |初版 [end] |
Copyright(C) 2002 Altmo
|
[C++ Index Top] [Prev] [Next] |