c++ 中仿函数初探
闲来无事试着使用 C++ 在 Editplus 中编写一个 Huffman 编码与解码的程序,遇到了需要对一个文件中的所有字符进行权重计算以创建每个字符的最终编码的过程,这其中有一个步骤是需要遍历已有的字符权重表以查找当前从文件中取得的字符是否已经存在于该表中,如果存在就将该表中的该字符权重加一,如不存在则需要新建一个存储 node 以存储该字符,并将该 node 结构添加到已有的权重表中。
考虑到需要在权重表中进行字符查找以及之后创建 Huffman Tree 时可能需要对该表各项进行排序所以选用 vector<Node>作为存储容器,查找及排序可以使用 algorithm 头文件当中的 sort 和 find 算法。
头文件及实现文件参见下面代码:
Huffman.h
#include <iostream> #include <fstream> #include <string> #include <vector> #include <algorithm>//for find_if func; #include <functional>//for bind2nd func; //#include <memory> #ifndef HUFFMAN_H #define HUFFMAN_H using namespace std; class Huffman { public: Huffman(void); //huffman(File file, File srcTable); void encode(const string& file); void decode(const string& file, const string& srcTable) const; ~Huffman(); private: //table node typedef struct { char letter; int level; int parent; int direction;//-1 for no parent, 0 for left, 1 right; }Node; vector<Node> nodeTable;//can be sorted; //仿函数,用于find_if,侦测字符是否已经存在; //template <typename T1, typename T2> class Comparer : public binary_function<Node, char, bool> { public: Comparer(const char ch):_ch(ch){}; const bool operator()(const vector<Node>::value_type& node, char ch) const { return node.letter == ch; } private: char _ch; }; }; #endif //g++ need a newline
Huffman.cpp
#include "Huffman.h" Huffman::Huffman(void) { //dummany; } void Huffman::encode(const string& file) { ifstream fin; fin.open(file.c_str()); char ch; while(fin.get(ch)) { if (nodeTable.size() != 0) { //vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),Compare(ch)); //仿函数 vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),bind2nd(Comparer(ch), ch)); //lambda 函数方式; //vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),[](const Node& node)->bool{return node.letter == ch;}); if (result == nodeTable.end()) { Node* node = new Node; node->letter = ch; node->level = 1; node->parent = 0; node->direction = -1; } else { result->level += 1; } } else { Node* node = new Node; node->letter = ch; node->level = 1; node->parent = 0; node->direction = -1; } } fin.close(); //huffman tree; } void Huffman::decode(const string& file, const string& srcTable) const { //dummany; } Huffman::~Huffman(void) { //dummany; } //g++ need a newline
先做如下说明:
1. 仿函数不是函数,而是一个类,这个类重载了()操作符;
2. 仿函数调用过程是这样的:find_if(nodeTable.begin(), nodeTable.end(), Comparer(ch))
中 Comparer(ch)只是创建了 Comparer 类的匿名方法,重载的 operator() 真正的调用是在
接下来将要看到的 find_if 模板函数的这一句 pred(*first);
3. 代码中不使用 find 而使用 find_if 是因为需要进行查找的不是 prime type 而是自行编写的符合
类型,find_if 的函数原型参考如下,从原型中可以看到第一个参数是以默认的方式进行的:
template<class InputIterator, class Predicate> InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred ) { for ( ; first!=last ; first++ ) if ( pred(*first) ) break; return first; }
4. bind2nd 函数的作用是将 二元算子(binary functor, bf) 转化为一元算子
(unary functor, uf) 还有一个类似的 bind1st ,使用时需要包含 functional 头文件;
(关于这个请自行放狗搜索)
5. 进行比较的仿函数需要继承 binary_functor<typename T1,typename T2,typename T3>,
T3 一般为 bool 值, binary_functor 原型如下:
template<class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; };
6. 这里使用的是 bind2nd 直接将得到的 char 参数 bind 到 Comparer 仿函数中,当然可以使用直
接传参数到 Comparer 仿函数中人的方法,从 Huffman.h 和 Huffman.cpp 的注释中可以看到存
在不同的可行方法;
这里是对这次使用仿函数的一次经验总结:
1. 先好好审视遇到的问题,试过能想到的解决之法后再放狗搜;
2. 国内网络上的资源少的可怜,重复的可恶,经常是 blog 作者几百篇的文章,转载的却占大多数,
大部分没什么营养,这里推荐一个 e 文的网站 www.stackoverflow.com
3. 记下你解决困难问题的方法,尽管可能从别人看来是很容易的问题,尽量少转载,经验教训是有
其存在价值的,尤其当他是真实的时候;