函數對象本質上是一個類對象,它重載了函數調用運算符 operator()
。調用運算符的函數體實現函數的功能。
例如,我們定義類 LessThan
:
class LessThan {
public:
bool operator() (const string &s1, const string &s2) {
return s1.size() < s2.size();
}
};
類 LessThan
包含調用運算符的重載,調用運算符的函數體實現了函數的功能:小於操作。
調用運算符的定義第一次看起來有點令人迷惑,因爲出現了兩個小括號。第一個小括號:
operator()
告訴編譯器我們在重載調用運算符。第二個小括號:
(const string &s1, const string &s2)
指定傳遞給調用運算符重載函數的形式參數。
函數對象的定義與普通類對象一樣:
LessThan lt;
string s1("lee");
string s2("leehao");
bool isLess = lt(s1, s2);
其中,語句 bool isLess = lt(s1, s2);
等價於 bool isLess = lt.operator()(s1, s2);
。
輸出:
1
函數對象一般作爲實參傳遞給泛型算法使用。
我們再定義一個函數對象,它包含一個被重載的調用運算符,判斷是否小於或等於指定的數值,這個指定的數值通過構造函數初始化:
class LessEqualValue {
public:
LessEqualValue(int val) : _val(val) {}
bool operator() (int val) {
return val <= _val;
}
private:
int _val;
};
標準庫函數 count_if
可以統計 vector 中符合條件的元素的個數,例如:
std::count_if(vecInt.begin(), vecInt.end(), LessEqualValue(10));
在調用 count_if
時,我們向其第三個參數傳遞了一個臨時函數對象 LessEqualValue(10)
,以統計 vecInt
向量中小於等於 10 的元素的個數。
完整的測試源代碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class LessEqualValue {
public:
LessEqualValue(int val) : _val(val) {}
bool operator() (int val) {
return val <= _val;
}
private:
int _val;
};
int main() {
vector<int> vecInt {10, 9, 13, 24, 4, 7, 15, 19, 3, 8, 2};
int n = std::count_if(vecInt.begin(), vecInt.end(), LessEqualValue(10));
cout << n << endl;
return 0;
}
輸出:
7
使用函數對象與使用函數指針相比較,有兩個方面的優點:
- 如果被重載的調用運算符是 inline 函數,則編譯器能夠執行內聯編譯,提供可能的性能優化
- 函數對象可以擁有任意數目的額外數據,可用來緩存操作中產生的結果
參考資料
《C++ Primer》第三版,中文版,Stanley B.Lippman 著,潘愛民等譯