函数对象(仿函数)

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<class T>
struct unary_function {
typedef T argumant_type;
typedef T result_type;
};
binary_function:作为二元函数基类,只定义了参数和返回值的类型
template<class T>
struct binary_function {
typedef T first_argument_type;
typedef T second_argument_type;
typedef T result_type;
};
less:用于返回较小值
template<class T>
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<class T>
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 <class T>
struct identity : public unary_function<T> {
const T& operator()(const T& x) const {return x;} //函数调用操作符
};
select1st: 返回键值,在 map 中会用到
template <class T>
struct select1st : public unary_function<T, typename T::first_type> {
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 <iostream>
#include "Vector.h"
#include "Functional.h"

using namespace std;

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

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

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

int main(){

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

    mySTL::vector<int>::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<int>::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<int> 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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容