仿函数(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 算法。

 #include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>//for bind2nd func; #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
 #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() != )
{
//仿函数
vector<Node>::iterator result = find_if(nodeTable.begin(),nodeTable.end(),bind2nd(Comparer(ch), ch)); if (result == nodeTable.end())
{
Node* node = new Node;
node->letter = ch;
node->level = ;
node->parent = ;
node->direction = -;
}
else
{
result->level += ;
}
}
else
{
Node* node = new Node;
node->letter = ch;
node->level = ;
node->parent = ;
node->direction = -;
}
}
fin.close(); //huffman tree; } void Huffman::decode(const string& file, const string& srcTable) const
{
//dummany;
} Huffman::~Huffman(void)
{
//dummany;
}

  此处仿函数调用过程是这样的:find_if(nodeTable.begin(), nodeTable.end(), Comparer(ch))中 Comparer(ch)只是创建了 Comparer 类的匿名方法,重载的 operator() 真正的调用是在接下来将要看到的 find_if 模板函数的这一句 pred(*first);代码中不使用 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;
}

  bind2nd 函数的作用是将 二元算子(binary functor, bf) 转化为一元算子(unary functor, uf) 还有一个类似的 bind1st ,使用时需要包含 functional 头文件;进行比较的仿函数需要继承 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;
};

  这里使用的是 bind2nd 直接将得到的 char 参数 bind 到 Comparer 仿函数中,当然可以使用直接传参数到 Comparer 仿函数中人的方法,从 Huffman.h 和 Huffman.cpp 的注释中可以看到存在不同的可行方法。

STL六大组件之——仿函数偷窥的更多相关文章

  1. STL —— STL六大组件

    注:以下内容摘自 http://blog.csdn.net/byxdaz/article/details/4633826 STL六大组件 容器(Container) 算法(Algorithm) 迭代器 ...

  2. STL 六大组件 功能与运用

    STL 提供六大组件,彼此可以组合套用: 1 容器(containers):各种数据结构,如vector,list,deque,set,map,用来存放数据,从实现的角度来看,STL容器是一种clas ...

  3. [转贴]从零开始学C++之STL(一):STL六大组件简介

    一.STL简介 (一).泛型程序设计 泛型编程(generic programming) 将程序写得尽可能通用 将算法从数据结构中抽象出来,成为通用的 C++的模板为泛型程序设计奠定了关键的基础 (二 ...

  4. STL六大组件简介

    一.STL简介 (一).泛型程序设计 泛型编程(generic programming) 将程序写得尽可能通用 将算法从数据结构中抽象出来,成为通用的 C++的模板为泛型程序设计奠定了关键的基础 (二 ...

  5. STL六大组件之——适配器代表大会

    适配器也是一种常用的设计模式: 将一个类的接口转换为另一个类的接口,使得原本因接口不兼容而不能合作的两个类可以一起运作.STL提供三种适配器:改变容器接口的容器适配器.改变迭代器接口的迭代器适配器以及 ...

  6. STL六大组件之——分配器(内存分配,好深奥的东西)

    SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不同的策略:当配置区块超过128bytes时,视之为“足够大”,便调用第一级配置器:当配置区小于1 ...

  7. STL六大组件之——迭代器这个东西

    迭代器:除了在其它语言中司空见惯的下标法访问容器元素之外,C++语言提供了一种全新的方法——迭代器(iterator)来访问容器的元素.迭代器其实类似于引用,指向容器中某一元素.换个方式来说,容器就是 ...

  8. STL六大组件之——算法小小小小的解析

    参考自侯捷的<stl源码剖析> stl算法主要分为非可变序列算法(指不直接修改其所操作的容器内容的算法),可变序列算法(指可以修改它们所操作的容器内容的算法),排序算法(包括对序列进行排序 ...

  9. STL六大组件之——容器知识大扫盲

    STL中的容器主要涉及顺序容器类型:vector.list.deque,顺序容器适配器类型:stack.queue.priority_queue.标准库中的容器分为顺序容器和关联容器.顺序容器(seq ...

随机推荐

  1. String与StringBuilder

    package com.wangzhu.string; /** * String类是final类,也就是说String类不能被继承,并且其成员方法都默认为final方法.<br/> * * ...

  2. 李洪强iOS开发之【零基础学习iOS开发】【02-C语言】02-第一个C语言程序

    前言 前面已经唠叨了这么多理论知识,从这讲开始,就要通过接触代码来学习C语言的语法.学习任何一门语言,首先要掌握的肯定是语法.学习C语言语法的目的:就是能够利用C语言编写程序,然后运行程序跟硬件(计算 ...

  3. 【Linux高频命令专题(21)】df

    概述 linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 显示指定磁盘文件的可用空间.如果没有文件名 ...

  4. Quartz动态添加、修改和删除定时任务

    任务调度开源框架Quartz动态添加.修改和删除定时任务 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz框架包含了调度器监听.作业和触 ...

  5. Mmap的实现原理和应用

    http://blog.csdn.net/edwardlulinux/article/details/8604400 很多文章分析了mmap的实现原理.从代码的逻辑来分析,总是觉没有把mmap后读写映 ...

  6. 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序(老罗学习笔记2)

    在前一篇文章中,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序.在这个名为hello的Linux内核驱动程序中,创建三个不同的文件节点来供用户空间访问,分别是传统的设备文 ...

  7. $.toJSON的用法或把数组转换成json类型

    1. html页面全部代码 <html> <head>     <title></title> <script src="../../S ...

  8. Java开发之反射的使用

    通过类名获取类. Class serviceManager = Class.forName("android.os.ServiceManager"); 获取方法 Method me ...

  9. [HDOJ1827]Summer Holiday(强连通分量,缩点)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1827 缩点后统计入度和当前强连通分量中最小花费,然后记录入度为0的点的个数和花费和就行了. /* ━━ ...

  10. [HDOJ2795]Billboard(线段树,单点更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795 题意:w*h的公告板要贴公告,公告是w*1的,每个公告有先后顺序,要使每个公告贴的位置尽可能地高 ...