大话STL第九期——仿函数(函数对象)

今天来到我们STL系列的第九期:仿函数的讲解

大话STL第九期——仿函数(函数对象)_第1张图片

 

文章目录

什么是仿函数?

仿函数的特点:

STL仿函数的分类:

谓词:

内建的仿函数:

算数仿函数:

关系仿函数:

逻辑仿函数:(不常用)


 

什么是仿函数?

仿函数作为STL六大组件中的其中一个,也称为函数对象,仿函数是一个能行使函数功能的,仿函数的语法几乎和普通函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。

仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。

 

仿函数的特点:

  1. 仿函数在使用时,可以像普通函数那样调用,可以有返回值
  2. 仿函数超出普通函数的概念,可以有自己的状态
  3. 函数对象可以作为参数传递

对于他的特点我们分别举例:

仿函数在使用时,可以像普通函数那样调用,可以有返回值

class Mytest {
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};
int main()
{
	Mytest test01;
	cout << test01(1, 2) << endl;
	//输出3
	return 0;
}
仿函数超出普通函数的概念,可以有自己的状态
class Mytest {
public:

	void operator()(string std)
	{
		cout << std << endl;
		this->count++;
	}
	int count=0;//记录函数调用多少次,内部自己状态
	//正常需要定义静态或者全局变量
};
void test02()
{
	Mytest test02;
	test02("okokok");
	test02("okokok");
	test02("okokok");
	test02("okokok");
	cout << test02.count << endl;
	//打印4次okokok
}
int main()
{
	test02();
	return 0;
}
函数对象可以作为参数传递
class Mytest {
public:

	void operator()(string std)
	{
		cout << std << endl;
	}
};
void doPrint(Mytest &t,string std)
{
	t(std);
}
int main()
{
	Mytest t;
	doPrint(t, "okfun");
    //输出okfun
	return 0;
}

STL仿函数的分类:

以操作数(operand)的个数划分,分为一元和二元仿函数;

以功能划分,可分为算数运算(Arithmetic)、关系运算(Rational)和逻辑运算(Logical);

谓词:

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数就称为一元谓词
  • 如果operator()接受两个参数就称为二元谓词

示例:

一元谓词:利用find_if找到大于5的数字

class Mytest {
public:

	bool operator()(int val)
	{
		return val > 5;
	}
};
int main()
{
	vector v{1,2,3,4,5,6,7,8,9 };
	auto it = find_if(v.begin(), v.end(), Mytest());
	if (it == v.end())
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到了:" << *it << endl;
	}
	return 0;
}

二元谓词:sort排序,同前几期介绍的自定义规则排序

class Mytest {
public:

	bool operator()(int val,int val2)
	{
		return val>val2;//从大到小排序
	}
};
template
void Show(vector &v)
{
	for (auto it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}
}
int main()
{
	vector v{1,2,3,4,5,6,7,8,9 };
	sort(v.begin(), v.end(), Mytest());
	Show(v);
	return 0;
}

内建的仿函数:

STL内部提供了一些仿函数,重载了许多(),便于与STL许多算法搭配使用,使用时我们需要引入头文件#include

算数仿函数:

template  T plus 加法仿函数
template  T minus 减法仿函数
template  T multiplies 乘法仿函数
template  T divides 除法仿函数
template  T modulus 取模仿函数
template  T negate 取反仿函数

其中只有negate取反为一元运算,其余都为二元运算,下面我会以乘法和取反举例:

void test01()
{
	negaten;
	cout << n(50.25) << endl;;
}
void test02()
{
	multipliesn;//对于二元运算只允许两个数据类型相同,所以只能写一种
	cout << n(1.1, 2.5);
}
int main()
{
	test01();//输出-50.25
	test02();//输出1.1*2.5
	return 0;
}

关系仿函数:

template  bool equal_to 等于
template  not bool equal_to 不等于
template  bool greater 大于
template  bool greater_equal 大于等于
template  bool less 小于
template  bool less_equal 小于等于

 

我们以大于来举例:

template
void Show(vector &v)
{
	for (auto it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main()
{
	vectorv{ 1,2,3,4,5,6,7,8,9,10 };
	Show(v);//

	sort(v.begin(), v.end(), greater());//从大到小
	Show(v);  //等同于上面二元谓词的栗子
	return 0;
}

主要实现对比的关系,最常用的为大于,因为默认的排序为小于,我们使用大于关系仿函数可以简单实现上面从大到小的自定义排序,观察sort源码也能发现: 

查看sort的声明,STL声明了两种模板

template            //需要传入一个_Pr _Pred 自定义的规则
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last)
    _Adl_verify_range(_First, _Last);
    const auto _UFirst = _Get_unwrapped(_First);
    const auto _ULast  = _Get_unwrapped(_Last);
    _Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));
}


  
template      //默认的排序 里面传入的是less<>{} 默认小于
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last)
    _STD sort(_First, _Last, less<>{});
}

逻辑仿函数:(不常用)

template  bool logical_and 逻辑与
template  bool  logical_or 逻辑或
template  bool logical_not 逻辑非

我们用逻辑非举例:

template
void Show(vector &v)
{
	for (auto it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

int main()
{
	vectorv{ false,true,true,false };
	Show(v);//0 1 1 0

	vector v2;
	v2要提前开辟大小,不然没有空间存放数据
	v2.resize(v.size());
	//搬运算法----transform
	transform(v.begin(), v.end(), v2.begin(),logical_not());
	Show(v2);//1 0 0 1
	return 0;
}

对于搬运算法transform,我们查看其源码声明

template 
_CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func)
FIRST对应源容器开始迭代器
LAST 对应源容器结束迭代器
DEST 对应目标容器开始迭代器
Func 对应函数或者函数对象

关于STL中的仿函数我们就到这里了,STL系列也马上结束了,下一期的算法和仿函数经常搭配使用,因此都要好好掌握,有兴趣的可以收藏整个系列,感谢观看!

 

你可能感兴趣的:(C++,c++,开发语言)