仿函數(functor),就是使一個類或類模板的使用看上去象一個函數。其實現就是類或類模板中對operator()進行重載,這個類或類模板就有了類似函數的行為。仿函數是智能型函數就好比智能指針的行為像指針,其就可看作是一個指針。但是智能指針是定義的一個類對象,所以在具備指針功能的同時也有其他的能力。仿函數的能力也可以超越operator()。因為仿函數可以擁有成員函數和成員變量,這意味著仿函數擁有狀態。另一個好處是可以在執行期初始化它們。
加法:plus<T>;減法:minus<T>;乘法:multiplies<T>;除法:divides<T>;求余:modulus<T>;否定:negate<T>
等於:equal_to<T>;不等於:not_equal_to<T>;大於:greater<T>;大於等於:greater_equal<T>;小於:less<T>;小於等於:less_equal<T>
除了否定為一元,其他都為二元仿函數。與:logical_and<T>;或:logical_or<T>;否:logical_not<T>
下面是一個哈夫曼編碼示例,遇到了需要對一個文件中的所有字符進行權重計算以創建每個字符的最終編碼的過程,這其中有一個步驟是需要遍歷已有的字符權重表以查找當前從文件中取得的字符是否已經存在於該表中,如果存在就將該表中的該字符權重加一,如不存在則需要新建一個存儲 node 以存儲該字符,並將該 node 結構添加到已有的權重表中。考慮到需要在權重表中進行字符查找以及之後創建 Huffman Tree 時可能需要對該表各項進行排序所以選用 vector<Node>作為存儲容器,查找及排序可以使用 algorithm 頭文件當中的 sort 和 find 算法。
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include <vector> 5 #include <algorithm> 6 #include <functional>//for bind2nd func; 7 8 #ifndef HUFFMAN_H 9 #define HUFFMAN_H 10 11 using namespace std; 12 13 class Huffman 14 { 15 public: 16 Huffman(void); 17 //huffman(File file, File srcTable); 18 void encode(const string& file); 19 void decode(const string& file, const string& srcTable) const; 20 ~Huffman(); 21 private: 22 //table node 23 typedef struct 24 { 25 char letter; 26 int level; 27 int parent; 28 int direction;//-1 for no parent, 0 for left, 1 right; 29 }Node; 30 vector<Node> nodeTable;//can be sorted; 31 32 //仿函數,用於find_if,偵測字符是否已經存在; 33 //template <typename T1, typename T2> 34 class Comparer : public binary_function<Node, char, bool> 35 { 36 public: 37 Comparer(const char ch):_ch(ch){}; 38 39 const bool operator()(const vector<Node>::value_type& node, char ch) const 40 { 41 return node.letter == ch; 42 } 43 44 private: 45 char _ch; 46 }; 47 }; 48 49 #endif
1 #include "Huffman.h" 2 3 Huffman::Huffman(void) 4 { 5 //dummany; 6 } 7 8 void Huffman::encode(const string& file) 9 { 10 ifstream fin; 11 fin.open(file.c_str()); 12 char ch; 13 while(fin.get(ch)) 14 { 15 if (nodeTable.size() != 0) 16 { 17 //仿函數 18 vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),bind2nd(Comparer(ch), ch)); 19 20 if (result == nodeTable.end()) 21 { 22 Node* node = new Node; 23 node->letter = ch; 24 node->level = 1; 25 node->parent = 0; 26 node->direction = -1; 27 } 28 else 29 { 30 result->level += 1; 31 } 32 } 33 else 34 { 35 Node* node = new Node; 36 node->letter = ch; 37 node->level = 1; 38 node->parent = 0; 39 node->direction = -1; 40 } 41 } 42 fin.close(); 43 44 45 //huffman tree; 46 47 } 48 49 void Huffman::decode(const string& file, const string& srcTable) const 50 { 51 //dummany; 52 } 53 54 Huffman::~Huffman(void) 55 { 56 //dummany; 57 }
此處仿函數調用過程是這樣的:find_if(nodeTable.begin(), nodeTable.end(), Comparer(ch))中 Comparer(ch)只是創建了 Comparer 類的匿名方法,重載的 operator() 真正的調用是在接下來將要看到的 find_if 模板函數的這一句 pred(*first);代碼中不使用 find 而使用 find_if 是因為需要進行查找的不是 prime type 而是自行編寫的符合類型,find_if 的函數原型參考如下,從原型中可以看到第一個參數是以默認的方式進行的:
1 template<class InputIterator, class Predicate> 2 InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred ) 3 { 4 for ( ; first!=last ; first++ ) if ( pred(*first) ) break; 5 return first; 6 }
bind2nd 函數的作用是將 二元算子(binary functor, bf) 轉化為一元算子(unary functor, uf) 還有一個類似的 bind1st ,使用時需要包含 functional 頭文件;進行比較的仿函數需要繼承 binary_functor<typename T1,typename T2,typename T3>,T3 一般為 bool 值, binary_functor 原型如下:
1 template<class Arg1,class Arg2,class Result> 2 struct binary_function 3 { 4 typedef Arg1 first_argument_type; 5 typedef Arg2 second_argument_type; 6 typedef Result result_type; 7 };
這裡使用的是 bind2nd 直接將得到的 char 參數 bind 到 Comparer 仿函數中,當然可以使用直接傳參數到 Comparer 仿函數中人的方法,從 Huffman.h 和 Huffman.cpp 的注釋中可以看到存在不同的可行方法。