函数对象(仿函数)

1.1 知识点

  • 函数对象概述
  • 预定义函数对象
  • 辅助函数对象
  • 适配器
  • 函数对象使用方法

1.2 实验环境

  • g++
  • ubuntu 16.04

1.3 代码获取

可以通过以下链接获取本课程的源码内容,本次实验内容主要包含在文件Functional.h

//获取代码
wget http://labfile.oss.aliyuncs.com/courses/1166/mySTL.zip

//解压文件到Code目录
unzip -q mySTL.zip -d ./Code/

二、函数对象概述

函数对象是重载函数调用操作符的类的对象。即函数对象是行为类似函数的对象,又称仿函数,是一个能被当做普通函数来调用的对象。

函数对象与函数指针相比,有两个优点:第一是编译器可以内联执行函数对象的调用;第二是函数对象内部可以保持状态。

STL 中的众多算法,非常依赖于函数对象处理容器的元素。所以 STL 预定义了许多函数对象、谓词和适配器。

三、预定义和辅助函数对象

我们可以在 Functional.h 中预定义一些函数对象,以方便在以后的实验中直接调用。

首先在 include 目录下创建 Functional.h。

unary_function: 作为一元函数对象的基类,只定义了参数和返回值的类型
template
struct unary_function {
typedef T argumant_type;
typedef T result_type;
};
binary_function:作为二元函数基类,只定义了参数和返回值的类型
template
struct binary_function {
typedef T first_argument_type;
typedef T second_argument_type;
typedef T result_type;
};
less:用于返回较小值
template
struct less{
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;

result_type operator()(const first_argument_type& x, const second_argument_type& y){
    return x < y;
}

};
equal_to: 判断是否相等
template
struct equal_to{
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
result_type operator()(const first_argument_type& x, const second_argument_type& y){
return x == y;
}
};
identity: 验证同一性
template
struct identity : public unary_function {
const T& operator()(const T& x) const {return x;} //函数调用操作符
};
select1st: 返回键值,在 map 中会用到
template
struct select1st : public unary_function {
const typename T::first_type& operator()(const T& x) const {return x.first;}

四、适配器

函数对象适配器本质上任然是一个函数;函数对象适配器提供了对函数对象或者普通函数的操作,使其能够根据我们的需求来修改函数对象或者普通函数的功能。

使用函数对象适配器的步骤:

(1)首先让自定义的函数对象 public 继承一个父类。这里有两个选择:binary_function 和 unary_function。如果有两个参数选择前者。

(2)定义一个函数对象作为参数传入函数对象适配器。常见的函数对象适配器有:

绑定适配器 bind1st bind2nd (bind1st 绑定第一个参数, bind2nd 绑定第二个参数)
取反适配器 not1 not2 (not1 作用于一元函数对象,not2 作用于二元函数对象)
普通函数适配器 ptr_fun
作用于类中方法的适配器 mem_fun mem_fun_ref
(3)加 const

五、实例测试

我们在上面讲了预定义函数对象和适配器,在下面我们就来演示预定义函数和适配器的搭配。我们在 Test 文件夹下建立 functionaltest.cpp,在这里需要用到 vector 容器来测试,关于Vector 容器的内容,我们将在后面的实验中给大家讲解,这里我们直接使用 Vector.h的内容。该文件可以通过下载课程源码找到。

#include 
#include "Vector.h"
#include "Functional.h"

using namespace std;

class compare:public binary_function{//用于接收两个参数
public:
    bool operator()(int i, int num) const {
        return i > num;
    }
};

class comparetonum:public unary_function{//用于接收一个参数
public:
    bool operator()(int i) const {
        return i > 5;
    }
};

void print(int i,int j)//普通函数对象
{
    if (i > j){
        cout << i << " ";
    }
}

int main(){

    mySTL::vector  vec;
    for (int i = 0; i < 10; i++)
    {
        vec.push_back(i + 1);
    }

    mySTL::vector::iterator it = find_if(vec.begin(), vec.end(), bind2nd(compare(),6));//找出大于6的第一个数
    if (it == vec.end())
    {
        cout << "cannot find the number!" << endl;
    }
    else
    {
        cout << "find num: " << *it << endl;
    }

    mySTL::vector::iterator rit = find_if(vec.begin(), vec.end(), not1(comparetonum()));  //取反适配器的用法,找出小于5的第一个数
    if (rit == vec.end())
    {
        cout << "cannot find the number!" << endl;
    }
    else
    {
        cout << "find num: " << *rit << endl;
    }

    mySTL::vector vec1;
    for (int i = 0; i < 10; i++)
    {
        vec1.push_back(i);
    }

    cout<<"The num larger than 5: ";
    mySTL::for_each(vec1.begin(), vec1.end(), bind2nd(ptr_fun(print),5)); //使用ptr_fun将普通函数转换为函数对象,然后给函数对象绑定参数。
    cout << endl;

    return 0;
}

执行命令:

g++ functionaltest.cpp -std=c++11 -o functionaltest -I ../include

你可能感兴趣的:(函数对象(仿函数))