仿函数(函数对象)
仿函数是C++ 早期的称呼,C++ 标准规格定案采用的是函数对象
函数对象:一种具有函数特征的对象,从行为上看,中文使用仿函数更加突出
从调用角度看,可以像函数一样被调用
从被调用者角度看,用对象所定义的function call operator(函数调用运算符operator()
) 扮演函数的实质角色
操作功能:要将某种操作当做算法的参数,唯一的方法就是先将该操作(可能拥有数条以上的指令)设计为一个函数
设计计为一个函数使用的两种方式:
- 设计为一个函数,再将一个函数指针当做算法的一个参数
- 将该操作设计为一个所谓的仿函数(在语言层面上看是一个类class),在以该仿函数产生一个对象并以此对象作为方法的一个参数
实现上看:仿函数实际上就是一个行为类似函数的对象,实现该功能,类别定义中必须自定义(或说改写,重载)function call 运算子(operator() ),使用上可以通过对象后面加上一对小括号,以此调用仿函数所定义的operator()
仿函数的分类
- 按照操作数operand 得个数划分,可以分为一元仿函数和二元仿函数
- 按照功能划分,可以分为 算数运算 arithmetic 、关系运算 rational 、逻辑运算 logical 三大类
使用仿函数需要声明 头文件
仿函数可配接的关键
仿函数是STL 六大组件中体积最小,观念最简单,实现最容易的,在STL 中扮演一种策略角色(算法因为不同仿函数的介入而有不同的变异行为,算法的本质是不变的)
STL 仿函数应该有能力被函数配接器显示,彼此像积木一样的串接
要拥有配接能力,每一个仿函数必须定义自己的相应型别,根迭代器类似定义自己的5个相应型别
型别是为了让配接器能够取出,获得仿函数的某些信息,相应型别都只是一些typedef ,所有必要操作在编译期就全部完成了,对程序的执行效率没有任何影响,不带来任何额外负担
反函数得相应型别主要用来表现函数参数型别和传回值型别,STL 中只支持一元仿函数和二元仿函数(STL 不支持三元仿函数)分别定义型别类,类中没有data member 或 member function 唯有一些型别定义:仿函数只要依照需求选择继承其中一个class 变拥有类相应型别的能力
unary_function 一元仿函数相应型别
template <class Arg,class Result>
struct unary_function{
typedef Arg argument_type; // 参数类型
typedef Result result_type; // 返回值类型
};
binary_function 二元仿函数相应型别
template <class Arg1,class Arg2,class Result>
struct binary_function{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
按功能划分多种仿函数
算数类仿函数
STL 内建的算数类仿函数,支持加法,减法,乘法,模数(余数,modulus)否定
//加法
plus<T>
//减法
minus<T>
//乘法
multiplies<T>
//除法
divides<T>
//模取
modulus<T>
//否定
negate<T>
例:
template <class>
struct negate : public unary_function<T,T>{
T operator()(const T& x) const {
return -x;
}
}
关系运算类仿函数
STL 内建的关系运算符函数支持了等于、不等于、大于、大于等于、小于,小于等于,每一个都是二元运算符
//等于
equal_to<T>
//不等于
not_equal_to<T>
//大于
greater<T>
//大于等于
greater_equal<T>
//小于
less<T>
//小于等于
less_equal<T>
逻辑运算仿函数
STL 内建支持逻辑运算类仿函数,支持了逻辑运算中的AndOrNot三种运算
logical_and<T>
logical_or<T>
logical_not<T>
证同identity 、选择select、投射 project
某些访函数对传回的参数有刻意的选择或者刻意的忽略。使用这三个。不再设计时使用。而是在画出来一层。保证间接性,间接性是抽象化的重要工具。
idedtity 证同
任何数值通过此函数不会改变。
STL 使用在 RB-tree set 因为键值就是实值
struct identity:public unary_function<T,T>{
const T& operator()(const T&x) const {
return x;
}
};
select 选择
在一个元素中。选择组成部分,如pair 的两个元素的选择
STL 中RB-tree 中使用 map 的pair 第一个元素就是键值
template <class Pair>
struct select1st : public unary_funiction<Pair,typename Pair::first_type>{
const typename Pair::first_type& operator()(const Pair &x)const {
return x.first;
}
};
投射函数 project
将两个参数中的一个参数投射而出。
template <class Arg1,class Arg2>
struct project1st : public binary_function<Arg1,Arg2,Arg1>{
Arg1 operator()(const Arg1&x ,Arg2&) const{
return x;
}
}