c++仿函数及在STL中的应用

1 仿函数

1.1 前置知识

1.1.1 运算符重载

作用:实现两个自定义数据类型(比如两个结构体/类 相加)“相加” 的运算。

        可以认为,运算符重载的实质是编写以  “opertor 运算符”  作为名称的函数。运算符函数的语法格式如下:

返回值类型  operator运算符(形参表)
{
    ....
}

下面是“+”运算符重载的例子:

class Person {
public:
	Person() {};
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
	//成员函数实现 + 号运算符重载
	Person operator+(const Person& p) {
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}


public:
	int m_A;
	int m_B;
};

//全局函数实现 + 号运算符重载
//Person operator+(const Person& p1, const Person& p2) {
//	Person temp(0, 0);
//	temp.m_A = p1.m_A + p2.m_A;
//	temp.m_B = p1.m_B + p2.m_B;
//	return temp;
//}

//运算符重载 可以发生函数重载 
Person operator+(const Person& p2, int val)  
{
	Person temp;
	temp.m_A = p2.m_A + val;
	temp.m_B = p2.m_B + val;
	return temp;
}

void test() {

	Person p1(10, 10);
	Person p2(20, 20);

	//成员函数方式
	Person p3 = p2 + p1;  //相当于 p2.operaor+(p1)
	cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl;


	Person p4 = p3 + 10; //相当于 operator+(p3,10)
	cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl;

}

int main() {

	test();

	system("pause");

	return 0;
}

        实际上,一个普通函数,定义好入参,也可以实现 两个自定义数据类型(比如两个结构体/类 相加)“相加” 的运算;和“运算符重载函数”的区别就是 运算符重载函数的调用可以很自然,可以直接用 A+ B 的方式,潜移默化的调用运算符重载函数。

PS:我们可以直接用全局函数实现一个 运算符重载,也可以将运算符重载写在一个类里作为成员函数。

1.1.2 函数调用运算符 “()” 重载

类似于加号运算符重载,函数调用运算符 “()” 也可以重载。

class MyPrint
{
public:
	void operator()(string text)  //operator() 是函数名
	{
		cout << text << endl;
	}

};
void test01()
{
	//重载的()操作符 也称为仿函数
	MyPrint myFunc;
	myFunc("hello world");
}

int main() {

	test01();

	system("pause");

	return 0;
}

1.1.3 函数对象(仿函数)

        一句话:重载 函数调用操作符()的类的对象,称为函数对象。(例如,1.1.2小节中的 myFunc 、add 其实都是函数对象。

        由于函数对象的使用非常像函数的调用,因此函数对象又称为仿函数

        函数对象(仿函数)实现了把一个函数像一个对象一样去使用(作为参数传递、也可以有成员变量),把一个对象像一个函数一样去使用(对象可以像函数一样调用),功能很强大轻便。如下示例:

#include <string>

//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
	int operator()(int v1,int v2)
	{
		return v1 + v2;
	}
};

void test01()
{
	MyAdd myAdd;
	cout << myAdd(10, 10) << endl;
}

//2、函数对象可以有自己的状态。我们可以记录这个函数调用了多少次(想像如果是普通函数调用次数,就需要一个全局变量);
class MyPrint
{
public:
	MyPrint()
	{
		count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl;
		count++; //统计使用次数
	}

	int count; //内部自己的状态
};
void test02()
{
	MyPrint myPrint;
	myPrint("hello world");
	myPrint("hello world");
	myPrint("hello world");
	cout << "myPrint调用次数为: " << myPrint.count << endl;
}

//3、函数对象可以作为参数传递
void doPrint(MyPrint &mp , string test)
{
	mp(test);
}

void test03()
{
	MyPrint myPrint;
	doPrint(myPrint, "Hello C++");
}

int main() {

	//test01();
	//test02();
	test03();

	system("pause");

	return 0;
}
匿名函数对象(仿函数)

        在函数对象像函数一样调用的过程中,有时候我们只关心两个操作数的运算,这样先定义一个函数对象,再用这个对象去调用其运算符函数,就显得稍微缓慢。为了轻便简洁使用,发明了 匿名函数对象。

        观察下面例子:为了实现两个数(可以是自定义数据类型)相加,方式1就是一个普通函数对象调用其运算符函数实例;方式2  则不是先起一个 函数对象名 add,然后再用add调用;而是直接用类型名MyAdd加一个()的方式临时表示一个‘函匿名数对象’,后面直接跟参数(如果没入参,可省略),就达到了我们的目的。这样的函数对象用完即释放,这样写很方便。

class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};

void test()
{	//方式1:
	MyAdd add;
	int ret = add(10, 10);
	cout << "ret = " << ret << endl;

    //方式2: 
	cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}
1.1.4 谓词
  • 返回bool类型的仿函数称为谓词

  • 如果operator()接受一个参数,那么叫做一元谓词

  • 如果operator()接受两个参数,那么叫做二元谓词

 一元谓词示例--仿函数在STL算法库 std::find_if 中的应用:
#include <vector>
#include <algorithm>

//1.一元谓词
struct GreaterFive{
	bool operator()(int val) {
		return val > 5;
	}
};

void test01() {

	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
    
	vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
	if (it == v.end()) {
		cout << "没找到!" << endl;
	}
	else {
		cout << "找到:" << *it << endl;
	}

}

int main() {

	test01();

	system("pause");

	return 0;
}

观察上面 std::find_if()函数的调用,我们先回顾 find_if()函数原型,

1.std::find_if()函数功能:按条件查找元素

2.函数原型
find_if( iterator beg, iterator end, _pred)
按值查找元素,找到的话返回指定位置的迭代器,找不到则返回结束迭代器位置
beg :开始迭代器
end :结束迭代器
_pred :函数或者谓词 (返回bool类型的仿函数)

 find_if()函数的参3需要传入一个谓词,我们传入了一个匿名函数对象(当然也可以自己定义一个实名函数对象传入),其也是个一元谓词。

二元谓词示例--仿函数在STL算法库 std::sort 中的应用:
#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
public:
	bool operator()(int num1, int num2)
	{
		return num1 > num2;
	}
};

void test01()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(40);
	v.push_back(20);
	v.push_back(30);
	v.push_back(50);

	//默认从小到大
	sort(v.begin(), v.end());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	cout << "----------------------------" << endl;

	//使用函数对象改变算法策略,排序从大到小
	sort(v.begin(), v.end(), MyCompare());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

上面两个 STL 算法都是使用比较频繁的,因此要熟悉其内在应用逻辑。 

2 仿函数在STL中的其他应用

STL内建函数对象(仿函数):

头文件 #include<functional>

  • 算术仿函数

仿函数原型:
template<class T> T plus<T>               //加法仿函数
template<class T> T minus<T>             //减法仿函数
template<class T> T multiplies<T>    //乘法仿函数
template<class T> T divides<T>         //除法仿函数
template<class T> T modulus<T>         //取模仿函数
template<class T> T negate<T>           //取反仿函数
  • 关系仿函数

template<class T> bool equal_to<T>                    //等于
template<class T> bool not_equal_to<T>            //不等于
template<class T> bool greater<T>                      //大于==
template<class T> bool greater_equal<T>          //大于等于
template<class T> bool less<T>                           //小于
template<class T> bool less_equal<T>               //小于等于
  • 逻辑仿函数

template<class T> bool logical_and<T>`              //逻辑与
template<class T> bool logical_or<T>`                //逻辑或
template<class T> bool logical_not<T>`              //逻辑非

 这里我们只举例介绍一个在STL中的应用常用的内建函数对象:greater

        头文件<functional>中已经建立好的仿函数greater(),让我们在使用sort从大到小排序的时候不用每次都自己写一个仿函数 mycompare():

#include <functional>
#include <vector>
#include <algorithm>

class MyCompare
{
public:
	bool operator()(int v1,int v2)
	{
		return v1 > v2;
	}
};
void test01()
{
	vector<int> v;

	v.push_back(10);
	v.push_back(30);
	v.push_back(50);
	v.push_back(40);
	v.push_back(20);

	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//自己实现仿函数
	//sort(v.begin(), v.end(), MyCompare());
	//STL内建仿函数  大于仿函数
	sort(v.begin(), v.end(), greater<int>());

	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值