C++ 函数对象&谓词&内建函数

目录

0函数对象

实际应用介绍 

函数对象超出了普通函数概念,内部可以保持状态 

函数对象作为参数传递

 1谓词

一元谓词举例:

 二元谓词举例:

2内建函数


0函数对象

重载函数调用操作符的类,其对象常被称为函数对象(function object)

它们的行为类似函数的对象,也叫仿函数(functor)其实就是重载“0”操作符,使得类对象可以像函数那样调用。

注意:

函数对象(仿函数)是一个类,不是一个函数

函数对象(仿函数)重载了“()”操作符,使得它可以像函数一样调用

分类:假定某个类有一个重载operator();而且重载的operator()要求获取一个参数,

我们就将这个类称为“一元仿函数(unary functor)

相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数(binary functor)

STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,

另一个版本则允许用户通过template参数的形式来指定所要采取的策略。

根据返回值的不同,返回值为bool类型的函数对象叫谓词

而系统自带的函数对象,叫内建函数

最简单的仿函数应用:

实际应用介绍 

class myPrint
{
public:
//    Myprint()
//    {
//        m_Num = 0;
//    }
//    int m_Num;
    void operator()(int num)
    {
        qDebug()<<num<<endl;
//        num++;
    }
};

操作: 

    myPrint MyPrintObject;
    MyPrintObject(111);

输出: 

其中的是个对象,调用括号实质是括号的重载,外形看起来非常像函数的调用。

同样的,也可以使用匿名对象进行仿函数的调用:

    myPrint()(1000);

函数对象超出了普通函数概念,内部可以保持状态 

增加成员变量,m_Num以此来保存仿函数的调用次数。 

class myPrint
{
public:
    int m_Num = 0;
    void operator()(int num)
    {
        qDebug()<<num<<endl;
        m_Num++;
    }
};

 操作如下:

    myPrint MyPrintObject;
    MyPrintObject(111);
    MyPrintObject(111);
    MyPrintObject(111);
    MyPrintObject(111);
    MyPrintObject(111);

    //函数对象超出了普通函数概念,内部可以保持状态
    qDebug()<<"myPrint使用次数:"<<MyPrintObject.m_Num;

输出: 

函数对象作为参数传递

打印接口

void doPrint(myPrint print,int num)
{
    print(num);
}

操作

    doPrint(MyPrintObject,11369);
    doPrint(myPrint(),22653);

输出

同样的,仿函数是一个类,可以作为某些接口的参数,比如set构造函数的排序规则,具体可见:

C++ STL(容器:list&set):https://blog.csdn.net/qq_41605114/article/details/105032788 

总结:

  1. 函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时间
  2. 函数对象超出普通函数的概念,函数对象可以有自己的状态
  3. 函数对象可内联编译,性能好,用函数指针几乎不可能
  4. 模板函数对象使函数对象具有通用性,这也是它的优势之一

 1谓词

谓词是指普通函数重载的operator()返回值是bool类型的函数对象(仿函数)

如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作一个判断式。

谓词:返回值是bool变量的仿函数

一元谓词举例:

一元谓词 

class GreatThen20
{
public:
    bool operator()(int val)
    {
        return val>20;
    }
};

 需要头文件:

#include<algorithm>

#include<vector>
using namespace std;

 具体操作:

    vector<int>v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);

    //查找第一个大于20的数字,第三个是函数对象,此处是匿名函数对象
    vector<int>::iterator pos = find_if(v.begin(),v.end(),GreatThen20());
    if(pos!=v.end())
    {
        qDebug()<<"找到大于20的数字为:"<<*pos;
    }
    else
    {
        qDebug()<<"未找到";
    }

输出:

find_if();需要三个参数:第一个首元素迭代器,第二个是结束迭代器,第三个是函数对象

返回一个迭代器,指向满足要求的元素位置。

 二元谓词举例:

二元谓词 

class MyCompare
{
public:
    bool operator()(int val1,int val2)
    {
        return val1>val2;
    }
};

 需要头文件:

#include<algorithm>

#include<vector>
using namespace std;

 具体操作: 

    vector<int>v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);

    sort(v.begin(),v.end(),MyCompare());

    for(vector<int>::iterator it = v.begin();it!=v.end();it++)
    {
        qDebug()<<*it;
    }

输出:

其中也有调用算法中的sort排序函数,第三个参数,使用函数对象,也就是谓词

2内建函数

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>//逻辑非

下面那取反、加法、大于作为示例:

    negate<int> n;
    qDebug()<<n(10);
    plus<int> p;
    qDebug()<<p(1,1);

输出:

    vector<int> v;
    v.push_back(1);
    v.push_back(4);
    v.push_back(3);
    v.push_back(6);
    v.push_back(7);
    sort(v.begin(),v.end(),greater<int>());
    for_each(v.begin(),v.end(),[](int val){cout<<val<<endl;});

 

而for_each中第三个参数,是匿名函数 ,算法的第三个参数,可以是内建函数,谓词,函数对象,也可以是函数指针

内建函数名<DataType> Object's name;

Object's name();

即可完成任务。

其中的加法,和二元谓词一样,二元谓词是人为的重载,内建是有现成的函数

发布了85 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41605114/article/details/105044227
今日推荐