C++中的仿函数functor

引子

先考虑一个简单的例子:假设有一个vector<string>,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码:

bool LessThan5Function(const string& str) {//寻找长度小于5的字符串
	return str.length() < 5;
}

void test() {
	vector<string> sVec{ "sadaw","srfafas","12" };
	int count = count_if(sVec.begin(), sVec.end(), LessThan5Function);//寻找容器中长度小于5的字符串的数量
}

在这里count_if函数的第三个参数是一个函数指针,返回一个bool类型的值。一般的,如果需要指定这个长度len作为参数传入的话,我们可能将函数写成这样:

bool LessThan5Function(const string& str,size_t len) {//寻找长度小于5的字符串
	return str.length() < len;
}

这个函数看起来比前面一个版本看起来OK,因为更加具有可操作性,但是他不能满足这个泛型函数count_if的参数要求:count_if要求的函数是unary function(仅带有一个参数的函数)。

我们如何才能在只能传入一个参数的情况下使用这个count_if,并且指定自己想要的参数,而且,不需要改变这个函数本身,比如如果我们要小于7的字符串数量,就得将传入的函数写成这样的话,正常人都会崩溃的

bool LessThan7Function(const string& str) {
	return str.length() < 7;
}

一般这种情况怎么办?

我们应该会想到用一个全局变量

int maxLength = 5;
bool LessThan5Function(const string& str) {//寻找长度小于5的字符串
	return str.length() < maxLength;
}

但是全局变量的缺点相信大家都很清楚:

  • 污染命名空间(多人协同,冲突)
  • 每次修改功能还是需要去修改这个全局变量
  • 不具有重复使用的功能(比如多个要用到这个函数指针的泛函数)

所以,说了这么多,我们需要的是一个什么东西呢?

我们需要一个能够实现函数功能,并且可以携带我们需要的数据(比如上面的字符串长度),最后最重要的:不会因为多个人同时使用,而造成功能冲突和混乱,的这样的一个东西

这就是我将要介绍的仿函数:

仿函数

借用一下百度百科的解释:

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

将上面的那个函数,用仿函数的方式改写了之后是什么样子?

class LessThan5Functor {
public:
	bool operator ()(const string& str) {//寻找长度小于5的字符串
		return str.length() < 5;
	}
};

就是一个简单的operator ()操作符的重写,但是仿函数和上面的函数指针不同的一点就是:它是一个对象

什么意思呢?

就是这是一个可以被实例化的、具有内存的、可存储数据的实体

想一下,上面的函数指针,我们想要携带数据进入那个count_if是多么的麻烦和不具有普适性,而仿函数的出现,就是为了兼容STL的标准

仿函数的使用

int main()
{
	greater<int > gt;
	cout << gt(1, 2) << endl;//false;   (1)
	cout << greater<int >()(6, 4) << endl;//true;    (2)

	system("pause");
	return 0;
}

上面的代码,就是一个仿函数的使用例子,我们定义了一个greater<int>的对象gt,(1) 中gt(1, 2)就是直接调用了greater<int> gt的的operator ()函数

而(2)是定义了一个greater<int>的局部变量,然后调用其operator ()函数,在(2)的这行代码结束后,这个greater<int>的局部变量就被回收了(临时对象)

善用仿函数的成员变量

针对最开始我们说的多个参数问题,我们可以如何解决呢?

int count = count_if(sVec.begin(), sVec.end(), LessThan5Functor);//寻找容器中长度小于5的字符串的数量

我们可以传入一个LessThanLenFunctor的仿函数对象作为参数,这个对象内部保存了长度信息,LessThanLenFunctor的对象实现如下:

class LessThanLenFunctor {
public:
	bool operator ()(const string& str) {//寻找长度小于5的字符串
		return str.length() < len;
	}
	LessThanLenFunctor(int l):len(l) {}
private:
	int len ;
};

这样我们就避免了使用全局变量的那几个问题,而且,非常优雅且有用,我们如何去使用这个仿函数呢?

如下,假设我们想查找长度小于3的字符串:

void test() {
	vector<string> sVec{ "sadaw","srfafas","12" };
	int count = count_if(sVec.begin(), sVec.end(), LessThanLenFunctor(3));//寻找容器中长度小于3的字符串的数量
}

我们只需要传入一个内部成员变量len为3的仿函数对象就行了,无论长度如何变化,有多少人要使用多少个不同的仿函数,你的仿函数的功能都不会发生变化

它既能像普通函数一样传入给定数量的参数(一个或者多个),还能存储我们需要的控制信息

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值