関数オブジェクト(擬似関数)
7553 ワード
関数ポインタは関数コールバックを実現するために広く用いられているが,C++はまた,関数オブジェクトである重要なコールバック関数を実現する方法を提供している.関数オブジェクト(演算子とも呼ばれる)は、()オペレータが再ロードされた通常のクラスオブジェクトです.したがって,文法的には,関数オブジェクトは通常の関数挙動と類似している.
関数ポインタの代わりに関数オブジェクトを使用するメリットはいくつかあります.
1>まず、オブジェクトは外部インタフェースを変更することなく内部で変更できるため、設計がより柔軟で、弾力性に富んでいます.
2>関数オブジェクトには、以前に呼び出した結果を格納するデータメンバーも備えられている.通常の関数を使用する場合は、以前に呼び出された結果を全行程またはローカル静的変数に格納する必要がありますが、全行程またはローカル静的変数には、私たちが見たくない欠陥があります.
3>次に、関数オブジェクトでコンパイラがインラインコールを実現し、パフォーマンスをさらに向上させることができます.これは関数ポインタではほとんど実現できない.
次に、関数オブジェクトの定義と使用方法を示します.まず、通常のクラスを宣言し、()オペレータを再ロードします.
リロード操作文では、リロードされたオペレータ名を表すため、最初の丸括弧は常に空であることを覚えておいてください.2番目の丸括弧はパラメータリストです.一般に、オペレータを再ロードする場合、パラメータの数は固定されますが、()オペレータを再ロードする場合は異なり、任意の複数のパラメータを持つことができます.
Squareに組み込まれている操作は1元(オペランドが1つしかない)なので、リロードされた「()」オペレータにもパラメータが1つしかありません.戻りタイプはパラメータタイプと同じです.この例ではintです.関数は、実パラメトリック平方の整数を返します.
関数オブジェクトの使用
次に、Callback()という関数を定義して、関数オブジェクトをテストします.Callback()には2つのパラメータがあります.1つはintで、1つはクラスSquareへの参照です.Callback()は、関数オブジェクトsquareを通常の関数名として使用します.
上のコードでは、squareは関数ではなくオブジェクトであることに注意してください.コンパイラは文:int val=square(n);
変換:int val=square.operator()(n);
通常、関数オブジェクトはコンストラクション関数とコンストラクション関数を定義しません.したがって、作成および破棄中に問題は発生しません.前述したように、コンパイラはリロードされたオペレータコードをインラインできるため、関数呼び出しに関連するランタイムの問題を回避できます.
上記の例を完了するために、Callback()のパラメータ伝達をメイン関数main()で実現します.
この例では、整数5と一時SquareオブジェクトをCallback()に渡し、プログラム出力25を出力する.
テンプレート関数オブジェクト
上記の例から分かるように、そのデータ型はintに制限されており、汎用性は関数オブジェクトの利点の一つであり、汎用性のある関数オブジェクトをどのように作成するか.メソッドは、テンプレートを使用します.つまり、リロードされたオペレータ()をクラスメンバーテンプレートとして定義し、doubleなどの任意のデータ型に関数オブジェクトを適用します.int 64またはchar:
上記の柔軟性を通常のコールバック関数で実現することはかなり困難である.
標準ライブラリ内の関数オブジェクト
C++標準ライブラリは、STLアルゴリズムに格納できるいくつかの有用な関数オブジェクトを定義します.例えば、sort()アルゴリズムは、3番目のパラメータとしてオブジェクト(predicate object)を判断する.判定対象はBoolean型の結果を返すテンプレート化された関数対象である.ソートの昇順または降順は、greater<>またはless<>をsort()に渡して強制的に実現できます.
#include//for greater<> and less<> #include//for sort() #include
using namespace std;
int main() { vector vi;
//..じゅうてんベクトル
sort(vi.begin(), vi.end(), greater() );//降順(descending)
sort(vi.begin(), vi.end(), less() );//昇順(ascending)}
関数ポインタの代わりに関数オブジェクトを使用するメリットはいくつかあります.
1>まず、オブジェクトは外部インタフェースを変更することなく内部で変更できるため、設計がより柔軟で、弾力性に富んでいます.
2>関数オブジェクトには、以前に呼び出した結果を格納するデータメンバーも備えられている.通常の関数を使用する場合は、以前に呼び出された結果を全行程またはローカル静的変数に格納する必要がありますが、全行程またはローカル静的変数には、私たちが見たくない欠陥があります.
3>次に、関数オブジェクトでコンパイラがインラインコールを実現し、パフォーマンスをさらに向上させることができます.これは関数ポインタではほとんど実現できない.
次に、関数オブジェクトの定義と使用方法を示します.まず、通常のクラスを宣言し、()オペレータを再ロードします.
class
Square
{
public
:
int
operator
() (
int
n)
{
return
n
*
n;
}
};
リロード操作文では、リロードされたオペレータ名を表すため、最初の丸括弧は常に空であることを覚えておいてください.2番目の丸括弧はパラメータリストです.一般に、オペレータを再ロードする場合、パラメータの数は固定されますが、()オペレータを再ロードする場合は異なり、任意の複数のパラメータを持つことができます.
Squareに組み込まれている操作は1元(オペランドが1つしかない)なので、リロードされた「()」オペレータにもパラメータが1つしかありません.戻りタイプはパラメータタイプと同じです.この例ではintです.関数は、実パラメトリック平方の整数を返します.
関数オブジェクトの使用
Square square;
int
y
=
square(
9
);
//
y = 81
次に、Callback()という関数を定義して、関数オブジェクトをテストします.Callback()には2つのパラメータがあります.1つはintで、1つはクラスSquareへの参照です.Callback()は、関数オブジェクトsquareを通常の関数名として使用します.
#include
using std::cout;
void Callback(int n, Square & square)
{
int val = square(n); // “()”
cout << val;
}
上のコードでは、squareは関数ではなくオブジェクトであることに注意してください.コンパイラは文:int val=square(n);
変換:int val=square.operator()(n);
通常、関数オブジェクトはコンストラクション関数とコンストラクション関数を定義しません.したがって、作成および破棄中に問題は発生しません.前述したように、コンパイラはリロードされたオペレータコードをインラインできるため、関数呼び出しに関連するランタイムの問題を回避できます.
上記の例を完了するために、Callback()のパラメータ伝達をメイン関数main()で実現します.
int
main()
{
Callback(
5
, Square() );
//
25
}
この例では、整数5と一時SquareオブジェクトをCallback()に渡し、プログラム出力25を出力する.
テンプレート関数オブジェクト
上記の例から分かるように、そのデータ型はintに制限されており、汎用性は関数オブジェクトの利点の一つであり、汎用性のある関数オブジェクトをどのように作成するか.メソッドは、テンプレートを使用します.つまり、リロードされたオペレータ()をクラスメンバーテンプレートとして定義し、doubleなどの任意のデータ型に関数オブジェクトを適用します.int 64またはchar:
class
GenericSquare
{
public
:
template T
operator
() (T t)
const
{
return
t
*
t;
}
};
int main()
{
GenericSquare square;
cout<< square(5.3333); // double
cout<< square(10000000000i64); // __int64
}
上記の柔軟性を通常のコールバック関数で実現することはかなり困難である.
標準ライブラリ内の関数オブジェクト
C++標準ライブラリは、STLアルゴリズムに格納できるいくつかの有用な関数オブジェクトを定義します.例えば、sort()アルゴリズムは、3番目のパラメータとしてオブジェクト(predicate object)を判断する.判定対象はBoolean型の結果を返すテンプレート化された関数対象である.ソートの昇順または降順は、greater<>またはless<>をsort()に渡して強制的に実現できます.
#include//for greater<> and less<> #include//for sort() #include
using namespace std;
int main() { vector vi;
//..じゅうてんベクトル
sort(vi.begin(), vi.end(), greater() );//降順(descending)
sort(vi.begin(), vi.end(), less() );//昇順(ascending)}