[C++] 函数对象(仿函数)

函数对象(function objects),之前叫做仿函数(functor)。顾名思义,就是函数产生的对象。从语言层面上来讲,它是一个类对象,实际上,我们把它当成一个函数来用。

先举个栗子(我也皮一下:D):

/*code block 1*/
#include <iostream>

using namespace std;

/*这里定义了一个类IsEqual并重载了其operator()函数,实际上这个类也只有这个函数*/
struct IsEqual {
	template <class T>
	bool operator()(const T& lhs, const T& rhs) {
		return lhs == rhs;
	}
};

int main() {
	IsEqual isEqual;

	cout << boolalpha << isEqual(3, 5) << endl;
	cout << isEqual(5, 5) << endl;
	cout << isEqual('c', 'c') << endl;

	return 0;
}
/*
输出为:
false
true
true
*/

当然,它不仅仅只能满足基础类型的相等比较,类类型也是可以的,但是需要被比较的类型重载operator==()函数,这里只是举个例子。

下面就给出类类型比较的例子:

/*code block 2*/
#include <iostream>

using namespace std;

struct IsEqual {
	template <class T>
	bool operator()(const T& lhs, const T& rhs) {
		return lhs == rhs;
	}
};

class People {
public:
    /*这里重载了双目operator==()运算符*/
    friend bool operator==(const People& lhs, const People& rhs) {
        return lhs.id == rhs.id;
    }

	People(string _id) : id(_id) {
	}

private:
	string id;
};

int main() {
	IsEqual isEqual;
	People a("0123");
	People b("1234");
	People c("0123");

    /*以下两种方法都是可以的*/
    cout << boolalpha << isEqual(a, b) << endl;
    cout << isEqual(a, c) << endl;

	cout << IsEqual()(a, b) << endl;
	cout << IsEqual()(a, c) << endl;

	return 0;
}
/*
输出为:
false
true
false
true
*/

(排版怎么乱了,很奇怪)

代码块2中给出了类类型也可以参与使用函数对象进行值的比较。isEqual是IsEqual的一个对象,而IsEqual()是一个临时对象,这两种方法都是可以的。

其实函数对象大多数时候不是这么定义的,而是按照如下的方式:

/*code block 3*/
#include <iostream>

using namespace std;

template <class T>
struct IsEqual {
	bool operator()(const T& lhs, const T& rhs) {
		return lhs == rhs;
	}
};

int main() {
	int i1 = 5;
	int i2 = 6;
	char ch1 = 'A';
	char ch2 = 'M';
	string str1 = "string";
	string str2 = "string";

	cout << boolalpha;
	cout << IsEqual<int>()(i1, i2) << endl;
	cout << IsEqual<char>()(ch1, ch2) << endl;
	cout << IsEqual<string>()(str1, str2) << endl;

	return 0;
}
/*
输出为:
false
false
true
*/

使用代码块3的方式,定义模板类而不仅是普通类的模板成员函数,在使用时可以更加直观的了解参与比较的对象的类型。

看到这里,有人就说了,这样有什么用吗,有点多此一举,明明可以直接比较,非要搞这些有的没的。

确实,如果函数对象的作用只是这么点,确实也没有存在的必要了。

其实,函数对象的主要作用是为了搭配STL算法使用。(《STL源码剖析》)

下面贴几张图:

也不给出太多的图了,sort()可以说是很经典的一个函数了。再它的custom版本中,需要给出三个参数,第三个参数是comp(我把它叫做比较器),如果该参数缺省,那就是默认采用升序排列。我们可以自己编写一个比较器(实质是一个函数对象),实现其他形式的排序。

/*code block 4*/
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

template <class T>
struct Greater {
	bool operator()(const T& lhs, const T& rhs) {
		return lhs > rhs;
	}
};

int main() {
	vector<int> ve = {1, 7, 8, 3, 2, 4, 6};

	for(auto &e : ve) {
		cout << e << " ";
	}
	cout << endl;

	sort(ve.begin(), ve.end());

	for(auto &e : ve) {
		cout << e << " ";
	}
	cout << endl;

    /*调用自己实现的Greater*/比较器
	sort(ve.begin(), ve.end(), Greater<int>());

	for(auto &e : ve) {
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
/*
输出为:
1 7 8 3 2 4 6
1 2 3 4 6 7 8
8 7 6 4 3 2 1
*/

上面的count_if()函数,功能是计算满足某个区间内所有满足某种条件的元素的个数。这个条件需要我们自己制定,这时候函数对象就要出马了。但是,我们发现对于不同的情况,这个条件千差万别,怎么办?

这个时候,我觉得lambda函数可以出来亮个相。

/*code block 5*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

int main() {
	vector<double> ve = {1.01, 2.9999, 3.000001, 3.0, 3.002, 2.999, 4, 3.5, 2.998};

	cout << ve.size() << endl;
	cout << count_if(ve.begin(), ve.end(), [](double d) {
		return fabs(d - 3.0) < 0.01;
	}) << endl;

	return 0;
}
/*
输出为:
9
6
*/

上面的count_if()函数实现的功能是统计ve中在(2.99,3.01)中的元素个数。

关于lambda函数,以后再来详述。

在<functional>头文件中提供了许多函数对象的原型(或者这里叫“仿函数”更合适)。许多我们可以直接拿来用,但是实现起来都不难,有兴趣可以自己实现。

所有函数声明都可以在http://www.cplusplus.com/reference/functional/中找到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值