C++函数对象Function Object

C++函数对象

定义:函数对象(Function Object)指的是定义了operator()的对象

一般形式:

class FunctionObjectType{
    public:
		void operator() (){
			//statements...
		}
};

优点:

  1. 比一般函数更灵巧,可以拥有状态
  2. 每个函数对象都有类型,可以将函数对象的类型当做template参数传递,容器类型也会因为函数对象类型的不同而不同
  3. 执行速度比函数指针稍快

用法一:以函数对象作为排序准则

std::set要求排序方法有“类型”,所以不能使用普通函数,但是可以使用函数对象。

#include <algorithm>
#include <iostream>
#include <set>
#include <string>
#include <vector>

using namespace std;

class Person
{
    public:
        Person(string lastname, string firstname)
            : _firstname(firstname)
            , _lastname(lastname)
        {
        }
        string firstname() const
        {
            return _firstname;
        }
        string lastname() const
        {
            return _lastname;
        }

    private:
        string _firstname = nullptr;
        string _lastname = nullptr;
};

class PersonSortCriterion
{
    public:
        bool operator()(const Person& p1, const Person& p2) const
        {
            return p1.lastname() < p2.lastname() || 
				   (p1.lastname() == p2.lastname() && p1.firstname() < p2.firstname());
        }
};

int main(void)
{
    set<Person, PersonSortCriterion> coll;
    Person p1("yu", "g");
    Person p2("an", "yu");
    Person p3("xiao", "ming");
    Person p4("xi", "biaoge");
    Person p5("u", "ong");
    coll.insert(p1);
    coll.insert(p2);
    coll.insert(p3);
    coll.insert(p4);
    coll.insert(p5);
    for (auto i : coll) {
        cout << i.lastname() << ", " << i.firstname() << endl;
    }

    return 0;
}

用法二:使用函数对象的内部状态

只要改变operator()就可以产生复杂的序列。
默认情况下,函数对象进行值传递,一次算法不会改变函数对象的状态。
如:

IntSequence seq(1);
std::generate_n(back_inserter(coll), 9, seq);

这种方式会使得从一开始产生序列。

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>

class IntSequence
{
    private:
        int value;
    public:
        IntSequence (int initialValue) : value(initialValue) {}

        int operator()()
        {
            return value++;
        }

        int getValue()
        {
            return value;
        }
};

int main(void)
{
    std::list<int> coll;
    //插入数值:1~9
    std::generate_n(back_inserter(coll), 9, IntSequence(1));
    for (auto i : coll) {
        std::cout << i << " ";
    }

	std::cout << std::endl;

	//替换第二个数到最后一个数
	std::generate(std::next(coll.begin()),std::prev(coll.end()),IntSequence(42));
    for (auto i : coll) {
        std::cout << i << " ";
    }
	std::cout << std::endl;

    return 0;
}

从运用了函数对象的算法中获取结果

方法有三种:

  1. 在外部持有状态,并让函数对象指向它
  2. 以引用方式传递函数对象
  3. 利用for_each()算法的返回值

第一种方法:

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>

class IntSequence
{
    private:
        int& value;
    public:
        IntSequence (int& initialValue) : value(initialValue) {}

        int operator()()
        {
            return value++;
        }

        int getValue()
        {
            return value;
        }
};

int main(void)
{
    int a = 1;
    IntSequence seq(a);
    std::list<int> coll;
    //插入数值:1~9
    std::generate_n<std::back_insert_iterator<std::list<int>>, int, IntSequence&>(std::back_inserter(coll), 9, seq);
    for (auto i : coll) {
        std::cout << i << " ";
    }

    std::cout << std::endl;
    std::cout << "a = " << a << std::endl;

    //再次插入10~13
    std::generate_n(std::back_inserter(coll), 4, seq);
    for (auto i : coll) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "a = " << a << std::endl;

    return 0;
}

第二种方法:

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>

class IntSequence
{
    private:
        int value;
    public:
        IntSequence (int initialValue) : value(initialValue) {}

        int operator()()
        {
            return value++;
        }

        int getValue()
        {
            return value;
        }
};

int main(void)
{
    IntSequence seq(1);
    std::list<int> coll;
    //插入数值:1~9
    std::generate_n<std::back_insert_iterator<std::list<int>>, int, IntSequence&>(std::back_inserter(coll), 9, seq);
    for (auto i : coll) {
        std::cout << i << " ";
    }

    std::cout << std::endl;
    std::cout << seq.getValue() << std::endl;

    //再次插入42~45
    std::generate_n(std::back_inserter(coll), 4, IntSequence(42));
    for (auto i : coll) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    std::cout << seq.getValue() << std::endl;

    return 0;
}

第三种方法:for_each()算法可以回传函数对象的状态
在这个程序中for_each()会返回函数对象,也就是以一个MeanValue对象

#include <iostream>
#include <vector>
#include <algorithm>

class MeanValue
{
    private:
        long num;
        long sum;
    public:
        MeanValue() : num(0), sum(0) {}

        void operator()(int elem)
        {
            ++num;
            sum += elem;
        }

        double meanvalue()
        {
            return static_cast<double>(sum) / static_cast<double>(num);
        }
};

int main(void)
{
	std::vector<int> coll = {2,4,56,453,35,7789,9,454,111,24,9012};
	MeanValue mv = std::for_each(coll.begin(),coll.end(),MeanValue());
	std::cout << "mean value = " << mv.meanvalue() << std::endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值