六、函数对象、谓词概念、内建函数对象

1.函数对象的概念

重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载"()"操作符,使得类对象可以像函数那样调用

注意:

  • 函数对象(仿函数)是一个类,不是一个函数
  • 函数对象(仿函数)重载了"()"操作符使得它可以像函数一样调用
#include <iostream>
#include <vector>
#include <string>
using namespace std;

void print(int index){
   cout<<"hello world..."<<index<<endl;
}

class myprint{
public:
    void operator()(int index){
        cout<<"hello world"<<index<<endl;
    }
}


//函数对象和普通函数对比
void test01(){
 
   print(10);
   myprint myp;
   myp(10);//效果一样!
}

//函数对象超出了普通函数的概念,可以保存函数调用状态
//统计函数调用次数?
int g_count = 0;
void print03(){
    g_count++;
}

class myprint03{
    myprint03():count(0){}
    void operator()(){
     count++;
    } 
    int count;
}

void test3(){
   print03();
   print03();

   cout<<g_count<<endl;//输出2

   myprint03 myp03;
   myp03();
   myp03();
   myp03();
   cout<< myp03().count<<endl;//输出3
}

//函数对象做参数,做返回值
class myprint04{
public:
    myprint04():count(0){};
    void operator()(int v){
       cout<<v<<" ";
       cout<<"hello world"<<endl;
       count++;
    }
    int count;
}


void test4(){
    vector<int> v;
    for(int i = 0 ; i < 10;i++){
        v.push_back(i);
    }

/*_Fn1是函数对象!!!!
template<class _InIt,class _Fn1> inline
_Fn1 for_each(_InIt _First,_InIt _Last,_Fn1 _Func)
{   //perform function for each element
    _DEBUG_RANGE(_First,_Last);
    _DEBUG_POINTER(_Func);
    _For_each(_Unchecked(_First),Unchecked(_Last),_Func);

    return (_STD move(_Func));
}

template<class _InIt,class _Fn1>inline
void _For_each(_InIt _First,_InIt _Last,_Fn1& _Func)
{   //perform function for each element
   for(;_First != _Last;++_First)_Func(*_First);//函数对象
}

*/
    myprint04 myp04;
    for_each(v.begin(),v.end(),myp04);//函数对象作参数//打印出来了 1 2 3 ....
    cout<<"count:"<<myp04.count<<endl;//发现是0!!明明可以打印hello world
    //原因是它传参过程中拷贝成了另一份,返回来了你没有接受!

    //所以应该还是
    myprint04 myp05 = for_each(v.begin(),v.end(),myp04);
    cout<<"count:"<<myp04.count<<endl;//0
    cout<<"count:"<<myp05.count<<endl;//10
}
int main(){
  // test3();
   test4();
   return 0;
}

2.谓词概念

谓词是指普通函数重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么就叫做一元谓词,如果接受两个参数,那么就叫做二元谓词。谓词可作为一个判断式

一元函数对象 应用举例:for_each
一元谓词 应用举例:find_if
二元函数对象 应用举例:transform
二元谓词 应用举例 sort

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//如果你写的函数对象接受一个参数,那么就叫做 一元函数对象
//如果你写的函数对象接受两个参数,那么就叫做 二元函数对象

//如果你写的函数对象或者普通函数接受一个参数,并且返回值是BOOL ,叫一元谓词
//如果你写的函数对象或者普通函数接受两个参数,并且返回值是BOOL ,叫二元谓词


//一元函数对象 应用举例:for_each
class print{
public:
    void operator()(int v){
      cout<<v<<" ";
    }
}

void print2(int v){
    cout<<v<<" ";
}

void test01(){
    vector<int> v;
    for(int i = 0;i<10;i++){
        v.push_back(i);
    }
    //print p;
    for_each(v.begin(),v.end(),print());//函数对象
    for_each(v.begin(),v.end(),print2);//普通函数
}


//一元谓词    应用举例:find_if    找到规则对比下的首元素
class mycompare{
public:
    bool operator()(int v){
       if (v > 7)return true;
       else return false;
    }
}
void test02(){
    vector<int> v;
    for(int i = 0;i<10;i++){
        v.push_back(i);
    }

    /*
    _Pr是bool类型别名
    template<class _InIt,class _Pr> inline
     _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred)
    {   // find first satisfying _Pred
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pred);
    return (_Rechecked(_First,
         _Find_if(_Unchecked(_First),_Unchecked(_Last),Pred)));
    }
    
    template<class _InIt,class _Pr> inline
    _InIt _Find_if(_InIt _First,InIt _Last,_Pr _Pred)
    {  // find first satisfying _Pred
    for(;_First != _Last;++_First)
       if(_Pred(*_First))
          break;
    return (_First);
    }
    */

    vector<int>::itertaor pos = find_if(v.begin(),v.end(),mycompare());//匿名函数对象
    if (pos == v.end())
    {
        cout<<"没找到"<<endl;
    }
    else{
        cout<<"找到了"<<*pos<<endl;//8
    }
}


//二元函数对象 应用举例:transform    对两个容器进行等位操作,完成后返回给第三个容器
class myplus{
public:
   int operator()(int v1,int v2){//v1是第一个容器中的元素 v2是第二个容器中的元素
      return v1 + v2;
   }
}


void test03(){
    vector<int> v1,v2,v3;
    for(int i = 0;i<10;i++){
        v1.push_back(i);
        v2.push_back(i+1);
    }

    /*

    template<class _InIt1,
        class _InIt2,
        class _OutIt,
        class _Fn2> inline
        _OutIt transform(_InIt1 _First1,_InIt1 _Last1,
            _InIt2 _First2, _OutIt _Dest, _Fn2 _Func)
    {   // transform [_First1, _Last1) and [_First2, ...) with _Func
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Func);
    _DEBUG_RANGE(_First1, _Last1);
    for(_First != _Last1)
       return (_Transform2(_Unchecked(_First1),_Unchecked(_Last1),
           _First2, _Dest, _Func,
           _Is_checked(_Dest)));

    return (_Dest);
    }

    template<class _InIt1,
        class _InIt2,
        class _OutIt,
        class _Fn2> inline
        _OutIt _Transform(_InIt1 _First1, _InIt1 _Last1,
        _InIt2 _First2, _OutIt _Dest, _Fn2 _Func)
        {   // transform [_First1, _Last1) and [_First2, ...) with _Func
        for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)
        *_Dest = _Func(*_First1, *_First2);
        return (_Dest);
        }
    
    */
    //v3最初没有开辟内存,会挂掉
    v3.resize(v1.size());

    //for_each借来打印一下
    for_each(v1.begin(),v1.end(),print2);
    cout<<endl;
    for_each(v2.begin(),v2.end(),print2);
    cout<<endl;
    for_each(v3.begin(),v3.end(),print2);
    cout<<endl;


    transform(v1.begin(),v1.end(),v2.begin(),v3.begin(),myplus());//结果放到v3容器中了
    cout<<endl;
   
    for_each(v1.begin(),v1.end(),print2);
    cout<<endl;
    for_each(v2.begin(),v2.end(),print2);
    cout<<endl;
    for_each(v3.begin(),v3.end(),print2);
    cout<<endl;
}

//二元谓词 应用举例 sort
class mycompare04{
public:
    bool operator()(int v1,int v2){
        return v1 > v2;//从大到小
    }
}
void test04(){

   vector<int> v;
   v.push_back(5);
   v.push_back(2);
   v.push_back(7);
   v.push_back(9);

   /*
   template<class _RanIt,
    class _Pr> inline
    void sort(_RanIt _First, _RanIt _Last, _Pr _Pred)
    {   // order [_First, _Last), using _Pred
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pred);
    _Sort(_Unchecked(_First), _Unchecked(_Last), _Last - _First, _Pred);
    }

   */
   for_each(v.begin(),v.end(),print2);
   cout<<endl;
   sort(v.begin(),v.end(),mycompare04());
   cout<<endl;
   for_each(v.begin(),v.end(),print2);
   cout<<endl;


}

int main(){

   test01();
   test02();
   test03();
   test04();
   return 0;
}

3.内建函数对象

STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些方函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使其内建函数对象,需要引入头文件#include <functional>

  • 6个算数类函数对象,除了negate是一元运算,其他都是二元运算
template<class T> T plus<T> //加法仿函数
template<class T> T minute<T> //减法仿函数
template<class T> T multiplies<T> //乘法仿函数
template<class T> T divides<T> //除法仿函数
template<class T> T modulus<T> //取模法仿函数
template<class T> T negate<T> //取反仿函数
  • 6个关系运算类函数对象,每一种都是二元运算
template<class T> bool equal_to<T> //等于
template<class T> bool not_equal_to<T> //不等于
template<class T> bool greater<T> //大于
template<class T> bool greater_equal<T> //大于等于
template<class T> bool less<T> //小于
template<class T> bool less_equal<T> //小于等于
  • 逻辑运算类运算函数,not为一元运算,其余为二元运算
template<class T> bool logical_and<T> //逻辑与
template<class T> bool logical_or<T> //逻辑或
template<class T> bool logical_not<T> //逻辑非

例子

#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;


void test01(){
    plus<int> myplus;//函数对象
    int ret = myplus(10,20);
    cout<<ret<<endl;//30

    plus<string> myplus2;
    string s1 = "aaa";
    string s2 = "bbb";
    string ret2 = myplus2(s1,s2);
    cout<<ret2<<endl;//aaabbb

    cout<<plus<int>()(10,20)<<endl;//匿名函数对象  30
}

//transform
void print(int v){
    cout<<v<<" ";
}
void test02(){
    vector<int> v1,v2,v3;
    for(int i = 0; i < 10;i++){
        v1.push_back(i);
        v2.push_back(i+1);

    }

    v3.resize(v1.size());
    transform(v1.begin(),v1.end(),v2.begin(),v3.begin(),plus<int>());//用预定义的函数对象!!!
    cout<<endl;
    for_each(v3.begin(),v3.end(),print);
    cout<<endl;
}


int main(){

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

推荐阅读更多精彩内容

  • C++运算符重载-上篇 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符和二元逻辑运算符4...
    Haley_2013阅读 2,261评论 0 51
  • C++运算符重载-下篇 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符和二元逻辑运算符4...
    Haley_2013阅读 1,428评论 0 49
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,094评论 0 13
  • 很实用的编程英语词库,共收录一千五百余条词汇。 第一部分: application 应用程式 应用、应用程序app...
    春天的蜜蜂阅读 1,329评论 0 22
  • 高考结束以后,怀着每天对成绩惴惴不安的心情在各个闺蜜家轮流住了一圈,是真的很放松啊,聊天聊了一晚也不觉得累。我跟她...
    uaremybelief阅读 167评论 0 0