C++関数ポインタまとめ

3897 ワード

c++を学ぶ過程で、ポインタは難点で、ポインタに慣れてから、もう一つ卵が痛い難点があります.それは関数ポインタです.本博文では、よく見られる様々な坑父の関数ポインタを詳しく紹介します.
ポインタの詳細については、このブログC++ポインタ詳細をお勧めします.
データと同様に、関数にもアドレスがあり、関数のアドレスはメモリに関数言語コードが格納されている開始アドレスです.関数ポインタはこのアドレスを指します.関数ポインタが指すタイプは、関数自体です.ポインタが指すタイプは、ポインタが指すメモリ領域のサイズを表していることがわかります.したがって、関数ポインタが指すタイプは、関数がメモリに占めるメモリのサイズです.関数の開始アドレスとサイズが分かったので,関数ポインタは関数の代わりに簡単に関数呼び出しを完了することができる.
一、最も簡単な関数ポインタ
変数には宣言と付与が含まれ、ポインタは例外ではなく、関数ポインタも例外ではありません.簡単な関数を見てみましょう
void add(int a, int b){
    cout << a + b << endl;
}

単純な加算でコマンドラインに出力される関数です.
では、関数ポインタで呼び出すにはどうすればいいのでしょうか.
1、声明:
void (*p1)(int a, int b);

関数ポインタの宣言は簡単で、基本的には1つのポインタで関数名を置き換えます.ポインタp 1のタイプはvoid(*)(int a,int b)であり、ポインタがある関数を指すポインタであることを示し、ポインタが指すタイプはvoid()(int a,int b)である
2、賦課:
p1 = add;

3、直接定義することもできます.
void (*p1)(int a, int b) = add;  

なお、関数void add(int a,int b)の関数名addは、関数のアドレスである.アドレスaddをポインタp 1に付与すると、関数ポインタp 1を介して直接関数を呼び出すことができる.
4、呼び出し:
(*p1)(1, 2);
p1(1, 2);

注意!歴史的理由から以上の2つの方式はいずれも関数を呼び出すことができる.
 
二、複数の関数ポインタを含む配列
このような場合、配列があり、配列の各要素が関数ポインタである場合、この配列をどのように定義すればいいのでしょうか.
1、解釈*p[n]と(*p)[n]
[]演算子の優先度は*より高いことが知られているため、p[3]は3つの要素を含む配列を表し、*p[3]の前の「*」は配列中の要素のタイプを示し、すなわち*p[3]は3つのポインタを指す配列を表す. 
p[3]は3つの要素を含む配列を表し、(*p)[3]はpを*pで置き換えたものであり、容易に考えられるが、(*p)[3]は3つの要素を含む配列を指すポインタを表す.
2、声明:
void (*p2[2])(int a, int b);

配列名はp 2、配列サイズは2、配列中の要素タイプはvoid(*)(int a,int b)であり、要素が関数を指すポインタであり、ポインタが指すタイプはvoid()(int a,int b)であることを示す.
3、賦課:
p2[1] = add;

理解は上と同じです.
4、呼び出し:
p2[1](2,3);
(*p2[1])(3,4); 

同じ2つの方法でもいいです.
 
三、「複数の関数ポインタを含む配列」へのポインタ
このタイトルはちょっと拗ねているようです.簡単に言えば、このポインタは、上記の「複数の関数ポインタを含む配列」を指す.実はとても簡単で、はっきり言って、上の中のp 2を1つのポインタで取って代わります.
1、声明:
void (*(*p3)[2])(int a, int b);

p 2を*p 3に置き換えることにほかならない.
2、付与、注意、ポインタである以上、使用前に初期化しなければならない.
p3 = &p2;
(*p3)[1] = add;

注意!実質的にp 2を*p 3に置き換える以上、c++11はauto p 3=&p 2と簡単に定義できる.void(*(*(*p 3)[2](int a,int b)=&p 2に代わった.
3、呼び出し:
(*p3)[1](1, 2);
(*(*p3)[1])(1, 2);