C++笔记---灵活的仿函数

什么是仿函数?

我的理解是:仿函数是类里面对()符号的重载。

为什么要使用仿函数?

举个例子:

对于学生结构体的排序问题,可能会有:先按成绩大小排序,若成绩相等就按照学号的先后顺序排序的排序规则。当然我们完全可以不用仿函数,纯手打一个简单的冒泡排序,给它加上一些交换相邻元素的判断条件就可以达到题目的要求,但这样太繁琐了,不如说,如果我都用了algorithm库里面的sort(),那为什么不把sort()的谓语写一下呢?而且sort()方法的时间复杂度还比手打的冒泡排序要小,代码也不容易出错。

还记得用C打了两年半的二分查找,别人C++一句upper_bound()就解决了,最重要的是我还没打对。

综上,仿函数的存在无疑是让代码更加地简洁,可以让写代码的速度变快,写代码的容错率也会变高。

怎么使用仿函数?

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class ps
{
	public:
	ps(){}
	//ps空的初始化是保证临时对象的存在
	//也就是保证仿函数的实现
	ps(int age,int score):age(age),score(score){}
	//ps的列表式初始化
	bool operator()(const ps& a,const ps& b)
	{
		count++;
		return a.score==b.score?a.age<b.age:a.score>b.score;
		//如果a和b的成绩不一样,那么成绩高的在前面
		//如果a和b的成绩一样就按照年龄排序,年龄越小越在前面
		//count 用来记录排序规则仿函数的调用次数
	}
	//为sort写的排序规则仿函数
	void operator()(const ps& a)
	{
		cout<<"年龄:"<<a.age<<" 成绩:"<<a.score<<endl;
	}
	//为for_each写的输出仿函数
	int age;
	int score;
	static int count;
    //类中的静态变量可以用来记录函数的调用次数
};
int ps::count = 0;

int main()
{
	vector<ps> a;
	a.push_back(ps(18,100));
	a.push_back(ps(22,100));
	a.push_back(ps(12,90));
	a.push_back(ps(20,110));
	cout<<"排序前:"<<endl;
	for_each(a.begin(),a.end(),ps());
	sort(a.begin(),a.end(),ps());
	cout<<"排序后:"<<endl;
	for_each(a.begin(),a.end(),ps());
	cout<<"记录:"<<ps::count<<endl;
	return 0;
}

构建仿函数前需要了解原函数的底层实现。比如for_each的底层实现就是一个for循环然后把每个元素代入仿函数执行,所以构建for_each的仿函数就只需要一个参数。所以了解algorithm库里面的实用算法的底层是有必要的!

但我们也可以用一般的类外函数实现仿函数的效果

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class ps
{
	public:
	ps(int age,int score):age(age),score(score){}
	//ps的列表式初始化
	int age;
	int score;
};

void look(const ps& a)
{
	cout<<"年龄:"<<a.age<<" 成绩:"<<a.score<<endl;
}

bool cmp(const ps& a,const ps& b)
{
   return a.score==b.score?a.age<b.age:a.score>b.score;
    //如果a和b的成绩不一样,那么成绩高的在前面
    //如果a和b的成绩一样就按照年龄排序,年龄越小越在前面	
}

int main()
{
	vector<ps> a;
	a.push_back(ps(18,100));
	a.push_back(ps(22,100));
	a.push_back(ps(12,90));
	a.push_back(ps(20,110));
	cout<<"排序前:"<<endl;
	for_each(a.begin(),a.end(),look);
	sort(a.begin(),a.end(),cmp);
	cout<<"排序后:"<<endl;
	for_each(a.begin(),a.end(),look);
	return 0;
}

 如何把函数作为另外一个函数的参数?

函数指针的定义方法:
指向的函数的返回值类型 (*指针名字)(指向的函数的参数类型列表)

#include <iostream>
#include <algorithm>
using namespace std;

//void (*pf)(pf参数类型列表)
//是指向返回值为void的pf函数

void my_function(int* start,int* end, void (*pf)(int))
{
	for(int *i=start;i!=end+1;i++)
    pf(*i);
}

void look(int val)
{
	cout<<val<<" "<<endl;
}

int main()
{
	int a[5]={1,3,2,4,5};
	my_function(a,a+4,look);
// 可以达到仿函数的效果
// 也是更为灵活!
	return 0;
}

最后总结一下,就拿上面的代码来说,仿函数就相当于是在给algorithm的my_function写look函数,所以这也是为什么了解algorithm的底层实现是那么重要了,当然我们也可以自己写自己的my_function和look,更加灵活但是也更加累,为什么不用现成的呢?(狗头保命)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没问题哒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值