STL源码剖析——仿函数(函数对象)

1 仿函数也称为函数对象,是一种具有函数特质的对象。调用者可以像函数一样的使用这些对象,例如在很多STL算法中,都可以看到,我们可以将一个方法作为模板内的参数传入到算法实现中,例如sort的时候我们可以根据我们传入的自定义的compare函数来进行比较排序。解决办法是使用函数指针,或者是将这个“操作”设计为一个所谓的仿函数,再用这个仿函数生成一个对象,并用这个对象作为算法的一个参数。

 

2 那为什么STL不使用函数指针而使用仿函数呢,因为函数指针不能满足STL对抽象性的要求,无法和STL的其他组件搭配以产生更加灵活的效果。

 

3 怎样实现这样一个仿函数呢?(可以直接使用对象名来使用函数)?答:我们必须自定义或者重载函数调用的运算符operator (),先产生类对象的一个匿名对象,再调用相应的函数。


 

4 STL仿函数应该有能力被函数适配器修饰,就像积木一样串接,然而,为了拥有配接能力,每个仿函数都必须定义自己的associative types(主要用来表示函数参数类型和返回值类型),就想迭代器如果要融入整个STL大家庭,也必须按照规定定义自己的5个相应的类型一样,这些assocaiative type是为了让配接器可以取得仿函数的某些信息,当然,这些associative type都只是一些typedef,所有必要操作在编译器就全部完成了,对程序的执行效率没有任何影响,不会带来额外的负担。

 

5 unary_function

用来呈现一元函数的参数类型和返回值类型

<span style="font-family:Microsoft YaHei;font-size:18px;">Template<class Arg, class Result>

Struct unary_function

{

    Typedef Arg argument_type;

    Typedef Result result_type;

}

//自定义的一元仿函数可以继承上类来获得类型定义

Template<class T>

Struct negate:public unary_function<T,T>

{

     T operator()(const T& x)const {return –x;}

};</span>

6 binary_function

用来呈现二元函数的第一个参数类型,第二个参数类型,和返回值类型

<span style="font-family:Microsoft YaHei;font-size:18px;">Template<class Arg1, class Arg2, class Result>

Struct binary_function

{

    Typedef Arg1 first_argument_type;

    Typedef Arg2 second_argument_type;

    Typedef Result result_type;

};

//use

Template<class T>

Struct plus: public binary_function<T,T,T>

{

    T operator()(const T& x, const T& y)const {return x+y ;}

};</span>

<span style="font-family:Microsoft YaHei;font-size:18px;">//适配器 前瞻(后文会介绍),使用组合而不是继承

Template<class Operation>

Class binder1st

{

Protected:

    Operation op;

    Typename Operation:first_argument_type value;

Public:

    Typename Operation::result type operation() ( const typename Operation::second_argument_type& x)const;

} ;</span>

7 STL内建的“算术类仿函数”,支持 加法,减法,乘法,除法,模数,否定



<span style="font-family:Microsoft YaHei;font-size:18px;">#include<iostream>

#include<functional>

Using namespace std ;

Int main()

{

Plus<int> plusobj;

Cout<<plusobj(3,5)<<endl;

Cout<<plus<int>(3,5)<<endl;

// accumulate( iv.begin(), iv.begin(),1 , multiplies<int>());

}</span>

8 STL内建的关系运算仿函数支持 等于,不等于,大于,大于等于,小于,小于等于


<span style="font-family:Microsoft YaHei;font-size:18px;">#include<iostream>

#include<functional>

Using namespace std;

Int main()

{

Equal_to<int> qual_to_obj;

Cout<equal_to_obj(3,5)<<endl;

Cout<<equal_to<int>(3,5)<<endl;

// sort ( iv.begin(), iv.end(), greater<int>());

}</span>

9 STL内建支持 逻辑运算仿函数, and or not


<span style="font-family:Microsoft YaHei;font-size:18px;">#include<iostream>

#include<functional>

Using namespace std;

Int main()

{

Logical_and<int> and_obj; //注意这里的参数类是int

Cout<<and_obj(true, true)<<endl;

Cout<<logical_and<int>(true,true)<<endl;

}</span>

10 证同(identity)、选择(select)、投射(project)
之所以不在STL中直接使用这些操作,而要再划分出一层,是为了间接性(间接性是抽象化的重要工具)。

证同函数
运用于<stl_set.h>中,因为set的键值即实值
template <class T>  //返回本身
struct identity : public unary_function<T, T> {
  const T& operator()(const T& x) const { return x; }
};

选择函数 
运用于<stl_map.h>,因为map中pair的第一个元素为键值
template <class Pair> //接受一个pair,返回第一个元素
struct select1st : public unary_function<Pair, typename Pair::first_type> {
  const typename Pair::first_type& operator()(const Pair& x) const
  {
    return x.first;
  }
};

template <class Pair> //接受一个pair,返回第二个元素
struct select2nd : public unary_function<Pair, typename Pair::second_type> {
  const typename Pair::second_type& operator()(const Pair& x) const
  {
    return x.second;
  }
};

投射函数

template <class Arg1, class Arg2> //传回第一参数,忽略第二参数
struct project1st : public binary_function<Arg1, Arg2, Arg1> {
  Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};

template <class Arg1, class Arg2> //传回第二参数,忽略第一参数
struct project2nd : public binary_function<Arg1, Arg2, Arg2> {
  Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
};






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值