c++ -- 函数对象

學習資源匯總來源於于中國MOOC,北大面嚮程序對象設計


一般定义是:如果一个类将()运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。
先给一个例子:

#include<iostream>
using namespace std;
class average{
public:
	int operator()(int a1,int a2,int a3){return (a1 + a2 + a3)/3; } 
};
int main()
{
	average a;
	cout<< "a.operator()(2,2,2) = "<<a.operator()(2,2,2)<<endl;
	average b;
	cout<<"b(2,2,2) = "<<b(2,2,2);
	return 0;
}

执行效果
在这里插入图片描述
代码分析:

  1. average a;是函数对象的定义;
  2. a.operator()(2,2,2)第一个括号的是对括号运算符的调用,第二个括号内是参数的传递;
  3. b(2,2,2)使所定义的对象能够调用()运算符;如此调用,类似于函数的普通调用,因此叫做函数对象。

与普通函数相比,函数对象比函数更加灵活,函数对象的优势:

  • 函数对象可以有自己的状态。我们可以在类中定义状态变量,这样一个函数对象在多次的调用中可以共享这个状态;
  • 函数对象有自己特有的类型。我们可以传递相应的类型作为参数来实例化相应的模板,比如说带参数的函数形参。

函数对象实例

STL中的模板

template<class InIt, class T, class Pred> 
T accumulate(InIt first, InIt last, T val, Pred pr);

其中

    pr 就是个函数对象,对[first,last)中的每个迭代器 I, 执行 val = pr(val,* I) ,返回最终的val。
    Pr也可以是个函数,或者函数指针。

在numeric 头文件中 accumulate 的源代码如下:

template <class InIt, class T, class Pred>
T accumulate(InIt first, Init last, T init, Pred op)
{
    for (; first != last; ++first)
        init = op(init, *first);
    return init;
};

其中pr只能是函数指针或者函数对象,而调用时的实参实参只能是函数名、函数指针或者函数对象。而T init是初始值,累加到该值上,然后返回,一般初始为0.
示例

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <numeric> 
#include <functional> 
using namespace std;
template<class T>
class sum{
public:
	T operator()(T &total,const T &value){
		total += value;
		return total;
	} 
};
int comp(int total,int value)
{
	return total + value * 4;
}
int main()
{
	const int SIZE = 10;
	int a[] = { 1,2,3,4,5,6,7,8,9,10 };
	vector<int> v(a,a + SIZE);
	int _sum = accumulate(v.begin(),v.end(),0,sum<int>());
	cout<<_sum<<endl;
	_sum = accumulate(v.begin(),v.end(),0,comp);
	cout<<_sum<<endl;
	return 0;
}

执行效果
在这里插入图片描述
其中

int _sum = accumulate(v.begin(),v.end(),0,sum<int>());

sum()实参是函数对象,括号是必须有的,说明是调用函数对象。
实例化

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

实例化之后最后一个参数是函数对象。而为什么不带括号呢?这是因为构造函数只会在最开始调用的时候进行一次赋值。

_sum = accumulate(v.begin(),v.end(),0,comp);

comp即调用普通的函数,不需要括号。
实例化为

int accumulate(accumulate(vector<int>::iterator first,
vector<int>::iterator last, int init,int (*pr)(int a,int b)){
	for ( ; first != last; ++first) 
		init = pr(init, *first);
	return init;
}

实例化之后最后一个参数是函数指针加参数列表,因为函数名字的类型是函数指针,因此本行将 accumulate 模板实例化后得到的模板函数定义如上;

如果对象中有需要赋值的变量,那么可以理解为先执行构造函数进行赋值,该值写在括号里就行,然后再利用该函数对象进行判断求值。
示例:

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <numeric> 
#include <functional> 
using namespace std;
template<class T>
class sum{
	int num;
public:
	sum(int i):num(i){  }
	T operator()(T &total,const T &value){
		for(int n = 1;n <= num;n++)
			total += value;
		return total;
	} 
};
int comp(int total,int value)
{
	return total + value * 4;
}
int main()
{
	const int SIZE = 10;
	int a[] = { 1,2,3,4,5,6,7,8,9,10 };
	vector<int> v(a,a + SIZE);
	int _sum = accumulate(v.begin(),v.end(),0,sum<int>(6));
	cout<<_sum<<endl;
	_sum = accumulate(v.begin(),v.end(),0,comp);
	cout<<_sum<<endl;
	return 0;
}

执行效果
在这里插入图片描述

函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同操作,而普通函数就无法做到这一点。因此函数对象的功能比普通函数更强大。

那么构造函数和函数对象调用如何区分呢?
在这里插入图片描述
需要类所定义胡对象单独调用函数即可。


STL 的< functional > 其他对象模板

如大小比较模板greater 的应用

  • list 有两个sort函数,不带参数的sort函数lst2.sort();,它将list中的元素 按 < 规定的比较方法升序排列。
  • list还有另一个sort函数: template void sort(T2 op); 可以用 op来比较大小,即 op(x,y) 为true则认为x应该排在前面。
    在这里插入图片描述
    其中copy类似于
template <class T1,class T2> 
void Copy(T1 s,T1 e, T2 x) {
	for(; s != e; ++s,++x) 
		*x = *s;
}

排序規則

  • 返回 true,意味着 a1 必须在 a2 前面
  • 返回 false,意味着 a1 并非必须在 a2 前面
  • 排序规则的写法,不能造成比较 a1,a2 返回 true 比较 a2,a1 也返回 true 否则sort会 runtime error
  • 比较 a1,a2 返回 false 比较 a2,a1 也返回 false,则没有问题
#include <iostream> 
#include <iterator> 
#include<vector>
using namespace std;
class Less {
public:
	bool operator ()(int a1, int a2)
	{
		if (a1 < a2)
			return true;
		else
			return false;
	}
};
bool comp(int a1, int a2)
{
	if (a1 < a2)
		return false;
	else
		return true;
}
template<typename T,typename pr>
T _max(T* p, int n, pr _less)
{
	T temp = p[0];
	for (int i = 0; i < n; i++)
		if (_less(temp, p[i]))
			temp = p[i];
	return temp;
}
int main()
{
	int a[] = { 1,2,6,4,2,3,4,8,5 };
	cout << _max(a, 9, Less()) << endl;
	cout << _max(a, 9, comp);
	return 0;
}

执行效果
在这里插入图片描述

发布了166 篇原创文章 · 获赞 45 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44116998/article/details/104274678