C++仿函数真好用

仿函数(functor),就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为。

简单举个例子,调用printFunctor pf("!"); pf("Hello world");,输出为Hello world!

class printFunctor
{
public:
	printFunctor(const string &s) : ss(s) {};

	void operator()(const string &str) const {
		cout << str << ss << endl;
	}
private:
	string ss;
};

用一个在数组中统计符合某些条件(比如大于一个数)的元素个数的例子来说明仿函数的作用吧。

用函数指针来写可以是这样:

bool isGreaterThan(double &num, double &thres)
{
	return (num > thres);
}

int countFun(double *array, const int &size, double th, bool (*fun)(double &, double &)){
	int cnt = 0;
	for(int i = 0; i < size; i++)
		if(fun(array[i], th))
			cnt++;
	return cnt;
}

这样做有2个问题:
1.数组元素类型是固定的(此处是double)。
很自然地可以想到,如果用函数模板是不是就可以支持其他类型呢?这样的话,countFun函数的第4个参数就需要传入一个“指向函数模板的函数指针”,并不可行。

在C++中,模板函数仅仅是一个用来生成函数的代码块,它本身是没有实体的,也就没有与“未被实例化的那些代码”相对应的程序代码块,所以也就无法对其取地址(不存在的东西,怎么会有具体的内存地址呢?)。只有在用具体类型代替模板参数,对该模板进行实例化以后才能有函数实体。
而函数指针要指向函数的入口地址,那么既然函数模板没有具体的内存地址,那么指向函数模板的函数指针如何得到地址呢?所以所谓的“函数模板指针”这个定义是无法通过以下的方法实现的:template<class T> void (*sample)(T &);
——https://www.cnblogs.com/superpig0501/p/3967576.html

2.作为countFun函数参数的函数指针bool (*fun)(double &, double &),形式已被确定,很难灵活应变(例如再传入2个参数用于指定元素上下限范围)。

下面来看看如何用仿函数解决上述问题。

1.用仿函数来支持多种数组元素类型:

template<typename T>
class operationFunctor
{
public:
	virtual bool operator()(const T &num) = 0; //Pure virtual function
};

template<typename T>
class gtFunctor : public operationFunctor<T>
{
public:
	gtFunctor(const T &_th) : thres(_th) {};
	bool operator()(const T &num) {
		return (num > thres);
	}
private:
	T thres;
};

template<typename T>
int countFun(T *arr, int size, operationFunctor<T> &op)
{
	int cnt = 0;
	for(int i = 0; i < size; i++)
		if(op(arr[i]))
			cnt++;
	return cnt;
}

countFun函数的第3个参数也可以写成类指针:

template<typename T>
int countFun(T *arr, int size, operationFunctor<T> *op)
{
	int cnt = 0;
	for(int i = 0; i < size; i++)
		if((*op)(arr[i])) //ATTENTION:(*op)(arr[i]), not *op(arr[i])!
			cnt++;
	return cnt;
}

2.用仿函数支持灵活地传参

template<typename T>
class gtLimFunctor : public operationFunctor<T>
{
public:
	gtLimFunctor(const T &_max, const T &_min, const T &_th) : max(_max), min(_min), thres(_th) {};
	bool operator()(const T &num) {
			return (num > min && num < max && num > thres);
	}
private:
	T max;
	T min;
	T thres;
};

最后附上主函数吧:

int main()
{
	printFunctor pf("!");
	pf("Hello world");

	const int size = 10;

	double doubleArr[size];
	for(int i = 0; i < size; i++)
		doubleArr[i] = i * 0.1;

	int intArr[size];
	for(int i = 0; i < size; i++)
		intArr[i] = i;

	int cnt1 = countFun(doubleArr, size, 0.6, isGreaterThan);
	cout << "Count1 " << cnt1 << endl;

	gtFunctor<double> doubleGt(0.4);
	int cnt2 = countFun<double>(doubleArr, size, doubleGt);
	cout << "Count2 " << cnt2 << endl;

	gtFunctor<int> intGt(7);
	int cnt3 = countFun<int>(intArr, size, intGt);
	cout << "Count3 " << cnt3 << endl;

	int cnt4 = countFun<double>(doubleArr, size, new gtFunctor<double>(0.8));
	cout << "Count4 " << cnt4 << endl;

	int cnt5 = countFun<int>(intArr, size, new gtLimFunctor<int>(6, 1, 3));
	cout << "Count5 " << cnt5 << endl;

	return 0;
}

参考:
C++ 仿函数


版权声明:本文为u013213111原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。