仿函数(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
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++ 仿函数