c++仿函数的应用

本文通过具体实例介绍了仿函数在C++中的应用,包括如何利用仿函数进行排序和查找操作,展示了仿函数简洁高效的特性。

首先介绍一个简单的例子

问题描述:

struct stRecordItem
{
char szname[_MAX_NAME_LEN_]; //物品名称
int dwBaseID; //基本ID
 int btItemLvl; //品阶
int ncount; //数量
__int64 i64Time; //记录这条信息的时间,如果有叠加的,按后一个的时间
};

list<stRecordItem> ListRecordItem;

现在要按照 ncount 降序,在 ncount 相同的时候,按btItemLvl的降序排列。

解决方法:

struct cmp
{
	bool operator()(const stRecordItem &st1,const stRecordItem &st2 )
	{
		if(st1.ncount<st2.ncount)
		{
			return false;
		}
		else if(st1.ncount == st2.ncount)
		{
			if(st1.btItemLvl < st2.btItemLvl)
			{
				return false;
			}
			else
				return true;
		}
		else
			return true;
	}
};
ListRecordItem.sort(cmp());

不言而喻,排序算法的简洁性与可扩展性都非常好。这个方法就是使用了stl常用的一种方法:仿函数

仿函数的概念:

仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

 

http://www.cnblogs.com/rereadyou/articles/2011048.html  有一个比较好的例子,实现了Huffman 编码与解码的程序,摘录如下:

 

使用 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; 
using namespace std;   
class Huffman {     
public:         
	Huffman(void);              
	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;        
	};
};  

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; 
} 

说明:

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 >,原型如下:

template<class Arg1, class Arg2, class Result>
struct binary_function 
{      
      typedef Arg1 first_argument_type;   
      typedef Arg2 second_argument_type;  
      typedef Result result_type;    
}; 


还有一些比较有用的博客,可以借鉴参考:

http://www.cnblogs.com/wzh206/archive/2010/03/26/1696983.html //介绍了一些STL的仿函数的应用

http://cunsh.ycool.com/post.1380153.html //实现了一个泛化的仿函数

http://www.soft-bin.com/html/2010/07/21/stl-cpp-functor-tutorial2.html //详细介绍了STL源码中对仿函数的使用并解析了remove_if、bind2nd的源代码(个人觉得非常具有参考性,推荐阅读)

http://blog.sina.com.cn/s/blog_491c65000100d62y.html  //实现了一个泛化的仿函数(>、<、== 、!=)的比较。

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值