C++基础知识(十九)--- 函数对象

目录

函数对象(重点)

函数对象应用实例1:在 accumulate 算法中的应用

函数对象应用实例2:在 sort 算法中的应用

eg:greater 模板的源代码如下:

sort算法有两个版本:

 函数对象和普通函数的区别:

谓词:

内建函数对象

算数类函数对象:(除了 negate是一元运算,其他都是二元运算)

关系运算类函数对象:(都是二元运算)

逻辑运算类仿函数:(not 为一元运算,其余为二元运算)

内建对象函数举例: 

c++中struct和class的区别


函数对象(重点)

C++函数对象详解(附带实例)

函数对象,就是可以当作函数使用的对象。

类中重载了(),这个类实例化的对象叫做函数对象(仿函数)。

  • 函数对象(仿函数)是一个类,不是一个函数;
  • 重载了“()”操作符,使得它可以像函数一样调用;

假定某个类有一个重载的 operator(),根据需要获取的参数个数分为:

  • 一元仿函数(unary functor):一个参数;
  • 二元仿函数(binary functor):两个参数。

函数对象的作用:作为算法策略。

函数对象应用实例1:在 accumulate 算法中的应用

STL 中有以下实现“累加”功能的算法(函数模板),该模板的功能是对(first,last)中的每个迭代器 I 执行 val = op(val, *I),返回最终的 val。

在头文件 numeric.h 中,accumulate 的源码如下:

#include<numeric>
template <class InIt, class T, class Fn>
T accumulate(const InIt first, const InIt last, T val, Fn op)
{
	for (; first != last; ++first)		
        val = op(val, *first);
	return val;
}

此模板被实例化后,op(val, *first) 必须要有定义,则 op 只能是函数指针或函数对象。因此调用 accumulate 模板时,形参 op 对应的实参只能是函数名、函数指针或者函数对象。

eg:通过 accumulate 模板求一个 vector 中元素的平方和。

#include<numeric>

template <class T>
void PrintInterval(T first, T last)
{ //输出区间[first,last]中的元素
	for (; first != last; ++first)
		cout << *first << " ";
	cout << endl;
}
int SumSquares(int total, int value)
{
	return total + value * value;
}
template <class T>
class SumPowers
{
private:
	int power;
public:
	SumPowers(int p):power(p){}
	const T operator()(const T& total, const T& value)
	{  //计算 value 的 power 次方,并加到total上
		T v = value;
		for (int i = 0; i < power - 1; ++i)
		{
			v = v * value;
		}
		return total + v;
	}
};

void test24()
{
	const int size = 5;
	int a1[] = { 1,2,3,4,5 };
	vector<int> v(a1, a1 + size);
	cout << "(1)";
	PrintInterval(v.begin(), v.end());
	
	int result = accumulate(v.begin(), v.end(), 0, SumSquares);
	cout << "(2)平方和: " << result << endl;

	result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));
	cout << "(3)立方和: " << result << endl;
	
	result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(4));
	cout << "(4)4次方和: " << result << endl;
}

注释:

1. 

int result = accumulate(v.begin(), v.end(), 0, SumSquares);

第四个参数是函数名。函数名字的类型是函数指针,因此本行将 accumulate 模板实例化后得到的模板函数定义如下:

int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, int(*op)(int, int))
{
	for (; first != last; ++first)
		val = op(val, *first);
	return val;
}

形参 op 是一个函数指针,而 op(val, *first) 就调用了指针 op 指向的函数,即函数 SumSquares。

2.

result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));

第四个参数是 SumPowes<int>(3),SumPowes 是类模板的名字,SumPowes<int> 就是类的名字。类的名字后面跟着构造函数的参数列表,就代表一个临时对象。

编译器在编译此行时,会将 accumulate 模板实例化为以下函数:

int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, SumPowers<int> op)
{
	for (; first != last; ++first)
		val = op(val, *first);
	return val;
}

形参 op 是一个函数对象,而 op(val, *first) 等价于:

op.operator()(val, *first);

即调用了 SumPowers<int> 类的operator 成员函数。

对比 1 和 2,函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同操作。???

函数对象应用实例2:在 sort 算法中的应用

 STL 中定义了一些函数对象类模板,都位于头文件 functional 中。

eg:greater 模板的源代码如下:

template<class T>
struct greater
{
	bool operator()(const T& x, const T& y)const
	{
		return x > y;
	}
};
#include<functional>
#include<algorithm>
#include<vector>

void test18()
{
	vector<int> v;
	v.push_back(4);
	v.push_back(7);
	v.push_back(3);

	sort(v.begin(), v.end(), greater<int>());

	for_each(v.begin(), v.end(), [](int val) {cout << val << " "; });
	//[](int val) {cout << val << " "; } //匿名函数
}

STL 中的排序模板 sort 能将区间从小到大排序。

sort算法有两个版本:

(1)该模板要求first、last是随机访问迭代器,元素比较大小是用 < 进行的。

template <class T>
void sort(const T first, const T last);

(2)该版本中,元素a、b比较大小是通过表达式 op(a,b) 进行的,op 定义了元素比较大小的规则。例如上边那个例子。

template <class T, class Pr>
void sort(const T first, const T last, Pr op);

eg:sort 算法

#include <algorithm>  //sort算法在此头文件中定义
template <class T>
void Printval(T first, T last)
{
	for (; first != last; ++first)
		cout << *first << " ";
	cout << endl;
}

class A
{
public:
	bool operator<(const A& a)
	{
		return this->v < a.v;
	}
public:
	int v;
	A(int n):v(n){}
};
//bool operator<(const A& a1, const A& a2) //也可以重载为A的const成员函数
//{ 
//	return a1.v < a2.v;
//}
bool GreaterA(const A& a1, const A& a2)
{
	return a1.v > a2.v;
}
struct LessA
{
	bool operator()(const A& a1, const A& a2)
	{
		return (a1.v % 10) < (a2.v % 10);
	}
};
ostream& operator<<(ostream& o, const A& a)
{
	o << a.v;
	return o;
}
void test25()
{
	int a1[4] = { 1,5,2,7};
	A a2[5] = { 43,1,8,45,62 };

	sort(a1, a1 + 4);
	cout << "(1) "; Printval(a1, a1 + 4);
	
	sort(a2, a2 + 5);
	cout << "(2) "; Printval(a2, a2 + 5); //按v的值从小到大排序	
    
	sort(a2, a2 + 5, GreaterA);  //按v的值从大到小排序
	cout << "(3) "; Printval(a2, a2 + 5);

	sort(a2, a2 + 5, LessA());  //按v的个位数从小到大排序
	cout << "(4) "; Printval(a2, a2 + 5);
}

注释:

1. 

sort(a2, a2 + 5, GreaterA); 

编译器将 sort 实例化得到的函数原型如下:

void sort(A* first, A* last, bool(*op)(const A&, const A&));

该函数在执行过程中,当要比较两元素大小时,就是看 op(a,b),本程序中 op 指向了 GreaterA,因此就用GreaterA定义的规则来比较大小。

2. 

sort(a2, a2 + 5, LessA()); 

编译器将 sort 实例化得到的函数原型如下:

void sort(A* first, A* last, LessA op);

该函数在执行过程中,当要比较两元素大小时,就是看 op(a,b),本程序中 op(a,b) 等价于op.operator(a,b),因此就用LessA定义的规则来比较大小。

 函数对象和普通函数的区别:

函数对象可以有自己的状态;(什么状态)

函数对象有类型,普通函数没类型;(怎么看的)

函数对象比普通函数执行效率高(成员函数自动申请成为内联函数);

谓词:

普通函数或重载的 operator() 返回值是 bool 类型的函数对象(仿函数)。

如果 operator 接收一个参数,则叫做一元谓词,如果接收两个参数,则叫做二元谓词

谓词可以作为一个判断式。

 

内建函数对象

STL内建了一些函数对象,即函数对象类模板。

分为:算数类函数对象、关系运算类函数对象、逻辑运算类仿函数。

这些仿函数所产生的对象,用法和一般函数完全相同,当然也可以产生无名的临时对象来履行函数功能。

使用内建函数对象,需要引入头文件 #include<functional>

算数类函数对象:(除了 negate是一元运算,其他都是二元运算)

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>    //小于等于

逻辑运算类仿函数:(not 为一元运算,其余为二元运算)

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

内建对象函数举例: 

 

c++中struct和class的区别

C++继承了C语言的 struct,并且加以扩充。因为考虑到对C兼容,所以C++保留了 struct,并做了一些扩展使其更适合面向对象。

① C语言中,struct 是一种数据类型,只能定义数据成员,而不能定义成员函数。C++中,struct 类似于class,在其中既可以定义数据成员,也可以定义成员函数。

② 默认的继承访问权。class 默认是 private,struct 默认是 public。

③ 默认访问权限。struct 作为数据结构的实现体,它默认的数据访问权限是 public 的;而 class 作为对象的实现体,它默认的成员变量访问权限是 private 的。

可以看出,struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值