C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析

STL- 函数对象

文章目录

  • STL- 函数对象
    • 1 函数对象
      • 1.1 函数对象概念
      • 1.2 函数对象使用
    • 2. 谓词
      • 2.1 谓词概念
      • 2.2 一元谓词
      • 2.3 二元谓词

1 函数对象

1.1 函数对象概念

概念:

  • 重载函数调用操作符的类,其对象常称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质: 函数对象(仿函数)是一个,不是一个函数

1.2 函数对象使用

特点:

  • 函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
  • 函数对象超出普通函数的概念,函数对象可以有自己的状态。因为函数对象本质是一个类,类中的成员属性可以记录状态
  • 函数对象可以作为参数传递

代码示例:

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

void test1()
{
	MyAdd myadd;//创建函数对象
	cout << "函数对象特点1:类似普通函数的调用,有参数、有返回值" << endl;
	cout << "myadd = " << myadd(10, 20) << endl;
	cout << string(50, '-') << endl;
}

//2、函数对象超出普通函数的概念,函数对象可以有自己的状态
class MyPrint
{
public:
	MyPrint()
	{
		this->count = 0;//初始化为0
	}
	void operator()(string test)
	{
		cout << test << endl;
		this->count++;//调用一次就记录一次
	}
	int count;//内部自己状态
};

void test2()
{
	MyPrint myprint;//创建函数对象
	cout << "函数对象特点2:函数对象可以有自己的状态" << endl;
	myprint("Keep working out!");//函数对象调用
	myprint("Keep fitting!");
	myprint("Keep slenderizing!");
	cout << "myprint调用次数为:" << myprint.count << endl;
	cout << string(50, '-') << endl;
}


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

void test3()
{
	MyPrint myprint;//创建函数对象
	cout << "函数对象特点3:函数对象作为参数传递" << endl;
	doPrint(myprint, "Bella要减肥");//函数对象作为参数传递
	cout << string(50, '-') << endl;
}

C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第1张图片

函数对象的特点1,其实在之前的学习笔记中有使用过,比如在list容器、set容器和map容器这几个容器的自定义数据类型排序以及内置数据类型的降序排序都使用过。
对于特点2,普通函数没有函数对象这样可以有成员属性来记录本身的状态,比如统计函数的调用次数,因为函数对象本质是一个类,类是可以有成员属性的。
对于特点3,函数对象可以做为一个参数传递。

总结: 仿函数写法非常灵活,可以作为参数进行传递。

2. 谓词

2.1 谓词概念

概念:

  • 返回bool类型仿函数称为谓词
  • 如果operator()接受一个参数,即形参列表中有一个参数,叫一元谓词
  • 如果operator()接受两个参数,即形参列表中有两个参数,叫二元谓词

2.2 一元谓词

代码示例:

class LargerthanSix
{
public:
	bool operator()(int val)//布尔类型的仿函数
	{
		return val > 6;
	}
};

void test1()
{
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(1 + i);
	}
	//在容器中找是否有大于6的元素可以用find_if
	//LargerthanSix() 创建匿名的函数对象(仿函数)
	vector<int>::iterator it = find_if(v.begin(), v.end(), LargerthanSix());
	//输出全部大于6的结果
	for (; it != v.end(); it++)
	{
		cout << "比6大的数有:" << *it << endl;
		if (it == v.end())
		{
			cout << "没有比6大的数!" << endl;
			break;
		}
	}
}

C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第2张图片

注意点:
首先,find_if函数的第一个和第二个参数是迭代器,表示一个区间中查找;第三个参数是仿函数,如果看到pred表示需要传入一个仿函数,下图示
C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第3张图片
其次,选中find_if→右键→转到定义 查看源码,find_if的返回值是一个迭代器
C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第4张图片
以上是find_if源码,说明如下

  1. find_if的参数列表:_First和 _Last都是迭代器,表示查找的区间,_Pred是仿函数,其中 _Last还使用了const来修饰。
  2. find_if的返回值:最后return的部分,返回的还是_First,说明最后返回的是一个迭代器。旁边的注释还说明了,find_if返回第一个满足仿函数条件的迭代器。
  3. find_if的for循环就是find_if的实现部分:_UFirst逐步遍历容器,循环结束的条件就是起始迭代器不等于结束迭代器。
  4. 通过if语句来实现满足条件值的查找:_Pred利用重载的()调用代码写的仿函数,通过星号* 解引用使得迭代器访问容器的数据,然后传给仿函数判断当前数据是否满足条件。具体来说,*_UFirst这个数据传给仿函数_Pred,如果返回真,说明找到满足条件的值,break结束循环,最后返回。如果返回假,_UFirst移动,直到_UFirst等于结束迭代器_ULast。

总结: 参数只有一个的谓词,称为一元谓词

2.3 二元谓词

示例:

class Mysort
{
public:
	bool operator()(int v1, int v2)//布尔类型的仿函数
	{
		return v1 > v2;
	}
};

void test1()
{
	vector<int> v;
	v.push_back(30);
	v.push_back(18);
	v.push_back(28);
	v.push_back(23);
	v.push_back(25);
	v.push_back(26);

	cout << "标准算法sort排序 升序\nv:  ";
	sort(v.begin(), v.end());
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
	{
		cout << *it << "  ";
	}
	cout << endl << string(40, '-') << endl;

	//使用函数对象 改变算法排序规则 降序
	cout << "\n制定算法sort排序 降序\nv:  ";
	sort(v.begin(), v.end(), Mysort());//Mysort() 匿名对象
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl << string(40, '-') << endl;
}

C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第5张图片
这个sort算法当中需要的是一个谓词,因此仿函数是bool类型。
C++ STL 函数对象的基本使用 一元谓词和二元谓词 find_if和sort源码解析_第6张图片

总结: 参数只有两个的谓词,称为二元谓词

你可能感兴趣的:(C++,泛型编程,语法学习笔记,c++)