C++における関数ポインタと関数オブジェクトの違いと関連

2937 ワード

関数呼び出しはC++の中で最も頻繁な操作で、関数は直接呼び出すことができて、関数のポインタを通じて呼び出すことができて、関数のオブジェクトを通じて間接的に呼び出すことができて、形式は多様化しています.次に、関数ポインタと関数オブジェクトの違いを見てみましょう.
1.関数ポインタ
1)定義
関数ポインタは、関数を指すポインタ変数です.Cコンパイルでは、各関数にエントリアドレスがあり、この関数を指す関数ポインタがこのアドレスを指します.関数ポインタには主に2つの役割があります.呼び出し関数と関数のパラメータとして使用されます.
2)宣言方法
データ型フラグ(ポインタ変数名)(パラメータリスト);
一般関数の宣言はint fun(int x);一方、関数ポインタの宣言方法はint(*fun)(int x);
前の(*fun)のカッコが必要です.これは、コンパイラがポインタとして返される関数を宣言するのではなく、関数ポインタを宣言する関数を宣言することを示します.後のパラメータは、この関数ポインタが指す関数パラメータによって決まります.
しかし、このような声明は私たちが非常に煩わしいと感じていることがあります.typedefは役に立ちます.私たちもこのように声明することができます.
      typedef int (*pf) (int x); 
      pf p;
これによりpは関数ポインタである.関数ポインタを使用して関数を呼び出す場合は、fun(x)、(*fun)(x)でいいです.もちろん、関数ポインタはリロードされた関数を指し、コンパイラはこれらのリロードされた関数を区別して正しい関数を指すことができます.
Demo:
typedef void (*P) ( char ,int );
void bar(char ch, int i) {
    cout<

例では、関数ポインタpは、宣言された関数bar()を指し、pによって関数を呼び出す.      
関数ポインタのもう一つの役割は関数のパラメータとして機能し、1つの関数のパラメータリストに関数ポインタを入力し、この関数でこの関数ポインタが指す関数を使用することができます.これにより、プログラムをより明確にし、簡潔にすることができます.このような用途テクニックは、多くの難しい問題を解決するのに役立ちます.小さなコストで十分な利益(速度+複雑さ)を得ることができます.
Demo:
//     ,     
typedef void (*P) ( char ,int );
void bar(char ch, int i) {
    cout<

上記の例では,まず1つの関数ポインタpをbar()に向け,foo()関数でpポインタを用いてbar()を呼び出し,目的を達成する.この特徴を少し利用すると、強力なプログラムを構築することができ、同じfoo関数だけで異なるbar関数の呼び出しを実現することができます.
2.関数オブジェクト
一般的な関数コールバックの意味では,関数オブジェクトと関数ポインタは同じであるが,関数オブジェクトには多くの関数ポインタが持たない点があり,関数オブジェクトはプログラム設計をより柔軟にし,関数のインライン呼び出しを実現し,プログラム全体の性能を加速させることができる.
クラスのオブジェクトに関数の機能がある場合、このオブジェクトを関数オブジェクトと呼ぶことができます.
2)使用方法
このオブジェクトのオペレータ()をリロードするだけで、次のようになります.
Demo:
class A{
     public:
        int operator() (int x){
            return x;
        }
};

A a;
a(1);

これによりaは関数オブジェクトとなり,a(1)を実行すると実際にはリロード記号()が利用される.
関数オブジェクトが「クラスオブジェクト」である以上、関数ポインタの代わりに関数パラメータリストで呼び出すことができます.ポインタがCのフラグであり,クラスがC++特有であるとすれば,ポインタ関数と関数オブジェクトの関係も前者と同じであるといえる.パラメータリストで関数を呼び出したい場合は、この関数機能を持つ関数オブジェクトを宣言してから、パラメータでこのオブジェクトを使用します.彼の機能と関数ポインタの機能は同じで、より安全です.
Demo:
class Fun{
    public:
        int operator() (int a, int b) {
           cout<

まず、関数オブジェクトクラスを定義し、()オペレータを再ロードします.最初の2つのパラメータを加算して出力し、addFunのパラメータリストでこのクラスオブジェクトを使用して、2つの加算機能を実現します.
汎用的な思考を用いて考えると,関数テンプレートクラスを決定し,一般的なタイプのデータの加算を実現することができる.
Demo:
class FunT{
    public:
      template
      T operator() (T t1, T t2) {
          cout<
template 
T addFunT(T t1, T t2, FunT& funt) {
    funt(t1,t2);
    return t1;
}
FunT funt;
addFunT(2,4,funt);
addFunT(1.4,2.3,funt);

STLではこの技術が広く使われている.関数オブジェクトの頻繁な呼び出しがプログラムの性能を大幅に低下させるとは思わないでください.多くの事実と実験は、関数オブジェクトを正しく使用するプログラムが他のプログラムよりずっと性能が速いことを証明しています.
関数オブジェクトはまたC++のために性能を高めたが、いくつかの複雑な問題と罠をもたらし、どのように柔軟に使用するかは、絶えず学ぶ必要がある.