首页 > 代码库 > 《STL源码剖析》学习笔记系列之七、八——仿函数和配接器
《STL源码剖析》学习笔记系列之七、八——仿函数和配接器
1、 仿函数
仿函数又名函数对象,具有函数性质的对象,就是传入一些参数,然后对参数进行某些运算,然后返回一个值。为了能够使行为类似函数,需要在类别定义中必须自定义function call 运算子operator()。
仿函数有如下几类:算术类仿函数(plus<T>、minus<T>)关系运算类仿函数(equal_to<T>、less<T>)逻辑运算类仿函数(logical_and<T>、logical_or<T>、logical_not<T>)证同、选择、投射。
1.1、可配接的关键
可配接指的是能够在类原有的基础上扩展成另外一个类。仿函数为此定义了两个类,分别代表一元仿函数和二元仿函数。之后的任何仿函数,根据功能需求选择其中一个类继承。具体代码如下:
一元仿函数
template<class Arg, classResult>
struct unary_function
{
typedef Arg argument_type;
typedef Result result_type;
};
template<class T>
struct negate:publicunary_function<T,T>
{
T operator()(const T& x) const {return -x;}
};
二元仿函数
template<class Arg1,classArg2,class Result>
struct binary_function
{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
template<class T>
struct plus:publicbinary_function<T,T,T>
{
T operator()(const T& x,const T& y) const {return x+y;}
};
2、配接器
配接器类似于转换器,它是一种设计模式,在原有的类型基础上扩展成为另外一个接口,使原本因为接口不兼容而不能合作的类型可以一起工作。
配接器分类如下:function adapter(改变仿函数接口)、container adapter(改变容器接口)、iterator adapter(改变迭代器接口)。
2.1 container adapter
最明显的例子就是stack和queue, 直接上代码,一看便知:
template<class T,classSequence=deque<T>>
class stack
{
protected:
Sequence c; //底层容器采用 deque
}
template<class T.classSequence=deque<T>>
class queue
{
protected:
Sequence c;
}
由上可知,class stack和class queue均以deque为底层容器,然后通过封主deque所有对外接口,只开放符合stack或queue原则的几个函数,所以我们称stack和queue是个配接器,一个作用于容器之上的配接器。
2.2 iterator adapter
书中针对迭代器适配器分三类进行描述:insert iterator、 reverseiterator、iostream iterator。后两种在实现技巧和理解上都相对复杂一些。通过实例来分析吧,代码如下:
int main()
{
1 ostream_iterator<int> outite(cout," ");
2 int ia[]={0,1,2,3,4,5};
3 deque<int> id(ia,ia+6);
4 copy(id.begin(),id.end(),outite);
5 cout<<endl; // 0 1 23 4 5
6 copy(ia+1,ia+2,front_inserter(id));
7 copy(id.begin(),id.end(),outite);
8 cout<<endl; //1 0 12 3 4 5
9 deque<int>::iterator ite=find(id.begin(),id.end(),4);
10 reverse_iterator<deque<int>::iterator>rite(ite)
11 cout<<*ite<<endl; //4
12 cout<<*rite<<endl; //3
}
由上可知,上述第1行代码,采用了iostream iteratoradapter将迭代起绑定到cout对象,组成一个ostream_iterator,拥有输出功能。第6行代码中front_inserter(id)是个辅助函数,方便客户端使用insert_iterator,调用该函数后实际产生一个对象迭代器适配器对象:
front_inserter_iterator<container>(x)。第10行代码中,通过reverse iterator迭代器配接器,转换了迭代器的方向,但是需要注意的是迭代器被逆转,虽然实体位置不变,即指针所在的位置不变,但是其所指的实体位置发生的改变,一个指向右,一个指向左。如下图所示:
2.3 function adapter
该部分是所有配接器中数量最庞大的一个族群。主要是通过对仿函数进行配接操作,组成更加丰富的表达式,简单的例子如下:
not1(bind2nd(less<int>(),12))
上式表述的是一个不小于12的表达式,其中less<int>()为仿函数,通过bind2nd这个配接器器辅助函数的操作转换成另外一种仿函数。
另外需要补充的是用户函数指针的ptr_fun配接器和用户成员函数指针的mem_fun\men_fun_ref。通过配接器操作能够将一般函数和成员函数当做仿函数使用,并传给STL算法。
《STL源码剖析》学习笔记系列之七、八——仿函数和配接器