STL简单函数对象(仿函数)的实现

1.简介

本文介绍的东西,在STL历史上有两个不同的名称。仿函数(functors)是早期的命名,C++标准定案后,采用的新名称是函数对象(function objects)。

函数对象,顾名思义,首先是对象(后面我们可以看到,函数对象是用struct而不是class定义的),其次,我们可以像调用函数一样,调用函数对象。这和函数指针很像,遗憾的是,函数指针不能满足面向对象的要求,不能满足STL对模板抽象性的要求,而且函数指针不能与STL其他组件搭配使用。于是聪明的科学家们发挥奇思妙想,给赤裸裸的函数裹上一层对象,并重载operator()方法,把函数的实现写到operator()中,这样我们就可以把函数当做对象传递,是不是很机智?

就实现而言,函数对象实际上就是一个“行为类似函数”的对象。为了能够“行为类似函数”,对象内必须重载operator()运算符,然后我们就可以在函数对象的后面加上一对小括号,以此调用函数对象定义的operator()。

函数对象和算法之间的关系如下图所示:

2.设计与实现

我用VS2013写的程序(github),函数对象的实现版本的位于cghSTL/version/
cghSTL-0.6.5.rar

本文介绍的函数对象需要以下文件:

1.    cghStl_funcbase.h,包含函数对象的基类,所有函数对象必须继承自基类,位于cghSTL/function
objects
/

2.       cgh_function_obj.h:本文的主角,包含算术类函数对象、关系运算类函数对象、逻辑运算类函数对象的实现,位于cghSTL/functionobjects/

3.       test_relational_function_obj.cpp,测试关系运算类函数对象,位于cghSTL/test/

4.      test_logical_function_obj.cpp,测试逻辑运算类函数对象,位于cghSTL/test/

5.    test_arithmetic_function_obj.cpp,测试算术类函数对象,位于cghSTL/test/;

2.1 函数对象的基类实现

STL函数对象应该有能力被函数配接器(function adapter)修饰,彼此像积木一样串接起来。为了拥有配接能力,每一个函数对象必须定义自己的相应型别(associative types),就像迭代器要融入STL大家庭,也必须依照规定,定义自己的5个型别一样。这些型别是为了让配接器能够取出函数对象的信息。型别定义都只是一些typedef,所有操作在编译期完成,对程序运行期的效率没有影响。

函数对象的型别主要用来表现函数参数类型和返回值类型。在cghStl_funcbase.h(cghSTL/functionobjects/)中,我们定义了两个classes,分别代表一元函数对象和二元函数对象的基类。任何函数对象必须继承自两个基类中的一个,只要继承了基类,便拥有了型别,也就拥有了配接能力。

cghStl_funcbase.h定义了函数对象的基类(共两个),代码如下

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:算术类(Arthmetic)仿函数的实现
******************************************************************/

#ifndef _CGH_STL_FUNC_BASE_H_
#define _CGH_STL_FUNC_BASE_H_

namespace CGH{

	/*
		unary_function 用来呈现一元函数的参数类型和返回值类型
		STL 规定,每一个 adaptable unary function 都应该继承 unary_function
	*/
	template<class arg, class result>
	struct unary_function
	{
		typedef arg		argument_type;
		typedef result	result_type;
	};

	/*
		binary_function 用来呈现二元函数的第一个参数类型、第二个参数类型、返回值类型
		STL 规定,每一个 adaptable binary function 都应该继承 binary_function
	*/
	template<class arg1, class arg2, class result>
	struct binary_function
	{
		typedef arg1		first_argument_type;
		typedef arg2		second_argument_type;
		typedef result		result_type;
	};

}

#endif

2.1 函数对象的实现

cgh_function_obj.h中包含了三类函数对象:算术类、关系运算类、逻辑运算类。

函数对象的设计比较简单,有疑问的地方已给出注释,代码如下

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:函数对象的实现
******************************************************************/

#ifndef _CGH_FUNCTION_OBJ_H_
#define _CGH_FUNCTION_OBJ_H_

#include "cghStl_funcbase.h"

namespace CGH{

#pragma region 算术类(Arithmetic)函数对象

	/* 相加 */
	template<class T>
	struct plus : public binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x + y;
		}
	};

	/* 相减 */
	template<class T>
	struct minus : public binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x - y;
		}
	};

	/* 相乘 */
	template<class T>
	struct multiplies : public binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x * y;
		}
	};

	/* 相除 */
	template<class T>
	struct divides : public binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x / y;
		}
	};

	/* 求余 */
	template<class T>
	struct modulus : public binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x % y;
		}
	};

	/* 取反 */
	template<class T>
	struct negate : public unary_function<T, T>
	{
		T operator()(const T& x) const
		{
			return -x;
		}
	};

#pragma endregion

#pragma region 关系运算类(Relational)函数对象

	/* 等于 */
	template<class T>
	struct equal_to : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x == y;
		}
	};

	/* 不等于 */
	template<class T>
	struct not_equal_to : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x != y;
		}
	};

	/* 大于 */
	template<class T>
	struct greater : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x > y;
		}
	};

	/* 小于 */
	template<class T>
	struct less : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

	/* 大于等于 */
	template<class T>
	struct greater_equal : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x >= y;
		}
	};

	/* 小于等于 */
	template<class T>
	struct less_equal : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x <= y;
		}
	};

#pragma endregion

#pragma region 逻辑运算类(logical)函数对象

	/* 逻辑与 */
	template<class T>
	struct logical_and : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x && y;
		}
	};

	/* 逻辑或 */
	template<class T>
	struct logical_or : public binary_function<T, T, bool>
	{
		bool operator()(const T& x, const T& y) const
		{
			return x || y;
		}
	};

	/* 逻辑非 */
	template<class T>
	struct logical_not : public unary_function<T, bool>
	{
		bool operator()(const T& x) const
		{
			return !x;
		}
	};

#pragma endregion

}

#endif

3.测试

3.1 算术类函数对象的测试

测试环节的主要内容已在注释中说明

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:测试算术类(Arthmetic)函数对象(仿函数)
******************************************************************/

#include "stdafx.h"
#include <iostream>
#include "cgh_function_obj.h"

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace::CGH;

	plus<int> plusObj;
	minus<int> minusObj;
	multiplies<int> multipliesObj;
	divides<int> dividesObj;
	modulus<int> modulusObj;
	negate<int> nagateObj;
	std::cout << std::endl;
	std::cout << "算术类函数对象共5个:plus、minus、multiplies、divides、modulus、negate" << std::endl << std::endl;
	std::cout << "************************ 测试算术类函数对象1 ***************************" << std::endl << std::endl;

	std::cout << "plusObj(3, 5) = " << plusObj(3, 5) << std::endl << std::endl;
	std::cout << "minusObj(3, 5) = " << minusObj(3, 5) << std::endl << std::endl;
	std::cout << "multipliesObj(3, 5) = " << multipliesObj(3, 5) << std::endl << std::endl;
	std::cout << "dividesObj(3, 5) = " << dividesObj(3, 5) << std::endl << std::endl;
	std::cout << "modulusObj(3, 5) = " << modulusObj(3, 5) << std::endl << std::endl;
	std::cout << "nagateObj(3) = " << nagateObj(3) << std::endl << std::endl;

	std::cout << "************************* 测试算术类函数对象2 **************************" << std::endl << std::endl;

	std::cout << "plus<int>()(3, 5) = " << plus<int>()(3, 5) << std::endl << std::endl;
	std::cout << "minus<int>()(3, 5) = " << minus<int>()(3, 5) << std::endl << std::endl;
	std::cout << "multiplies<int>()(3, 5) = " << multiplies<int>()(3, 5) << std::endl << std::endl;
	std::cout << "divides<int>()(3, 5) = " << divides<int>()(3, 5) << std::endl << std::endl;
	std::cout << "modulus<int>()(3, 5) = " << modulus<int>()(3, 5) << std::endl << std::endl;
	std::cout << "negate<int>()(3) = " << negate<int>()(3) << std::endl << std::endl;

	system("pause");
	return 0;
}

测试结果:

3.2 关系运算类函数对象的测试

测试环节的主要内容已在注释中说明

test_relational_function_obj.cpp

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:测试关系运算类(Relational)函数对象(仿函数)
******************************************************************/

#include "stdafx.h"
#include <iostream>
#include "cgh_function_obj.h"

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace::CGH;

	equal_to<int> equal_to_obj;
	not_equal_to<int>not_equal_to_obj;
	greater<int> greater_obj;
	greater_equal<int> greater_equal_obj;
	less<int> less_obj;
	less_equal<int> less_equal_obj;

	std::cout << std::endl;
	std::cout << "关系类函数对象共5个:equal_to、not_equal_to、greater 、\n\t\t\tgreater_equal、less、less_equal" << std::endl << std::endl;
	std::cout << "************************ 测试关系类函数对象1 ***************************" << std::endl << std::endl;

	std::cout << "equal_to_obj(3, 5) = " << equal_to_obj(3, 5) << std::endl << std::endl;
	std::cout << "not_equal_to_obj(3, 5) = " << not_equal_to_obj(3, 5) << std::endl << std::endl;
	std::cout << "greater_obj(3, 5) = " << greater_obj(3, 5) << std::endl << std::endl;
	std::cout << "greater_equal_obj(3, 5) = " << greater_equal_obj(3, 5) << std::endl << std::endl;
	std::cout << "less_obj(3, 5) = " << less_obj(3, 5) << std::endl << std::endl;
	std::cout << "less_equal_obj(3, 5) = " << less_equal_obj(3, 5) << std::endl << std::endl;

	std::cout << "************************* 测试关系类函数对象2 **************************" << std::endl << std::endl;

	std::cout << "equal_to<int>()(3, 5) = " << equal_to<int>()(3, 5) << std::endl << std::endl;
	std::cout << "not_equal_to<int>()(3, 5) = " << not_equal_to<int>()(3, 5) << std::endl << std::endl;
	std::cout << "greater<int>()(3, 5) = " << greater<int>()(3, 5) << std::endl << std::endl;
	std::cout << "greater_equal<int>()(3, 5) = " << greater_equal<int>()(3, 5) << std::endl << std::endl;
	std::cout << "less<int>()(3, 5) = " << less<int>()(3, 5) << std::endl << std::endl;
	std::cout << "less_equal<int>()(3, 5) = " << less_equal<int>()(3, 5) << std::endl << std::endl;

	system("pause");
	return 0;
}

测试结果:

3.3 逻辑类函数对象的测试

测试环节的主要内容已在注释中说明

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  [email protected]
*
*  文件内容:测试逻辑运算类(Logical)函数对象(仿函数)
******************************************************************/

#include "stdafx.h"
#include <iostream>
#include "cgh_function_obj.h"

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace::CGH;

	logical_and<int> logical_and_obj;
	logical_or<int> logical_or_obj;
	logical_not<int> logical_not_obj;

	std::cout << std::endl;
	std::cout << "逻辑类函数对象共3个:logical_and、logical_or、logical_not" << std::endl << std::endl;
	std::cout << "************************ 测试逻辑类函数对象1 ***************************" << std::endl << std::endl;

	std::cout << "logical_and_obj(3, 5) = " << logical_and_obj(3, 5) << std::endl << std::endl;
	std::cout << "logical_or_obj(3, 5) = " << logical_or_obj(3, 5) << std::endl << std::endl;
	std::cout << "logical_not_obj(3) = " << logical_not_obj(3) << std::endl << std::endl;

	std::cout << "************************* 测试逻辑类函数对象2 **************************" << std::endl << std::endl;

	std::cout << "logical_and_obj<int>()(3, 5) = " << logical_and<int>()(3, 5) << std::endl << std::endl;
	std::cout << "logical_or_obj<int>()(3, 5) = " << logical_or<int>()(3, 5) << std::endl << std::endl;
	std::cout << "logical_not_obj<int>()(3) = " << logical_not<int>()(3) << std::endl << std::endl;

	system("pause");
	return 0;
}

测试结果:

时间: 2024-08-28 15:57:54

STL简单函数对象(仿函数)的实现的相关文章

C++ STL 基础及应用(7) 函数对象(仿函数)

把函数作为对象是程序设计的新思维.STL 通过重载类中的 operator() 函数实现函数对象功能,不但可以对容器中的数据进行各种各样的操作,而且能够维护自己的状态.因此,与标准 C 库函数相比,函数对象更为通用. 本章将介绍函数指针的使用.函数对象的定义.引入目的.使用方法,C++98 标准和C++11标准下 STL 内置函数对象的详细介绍.适配器类的使用.包括 bind1st bind2nd not1 not2 mem_fun mem_fun_ref ptr_fun bind ref cr

STL中的仿函数

仿函数(functors)在C++标准中采用的名称是函数对象(function objects).仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求--函数指针无法和STL其他组件搭配,产生更灵活变化. 仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象.例如下面就是一个仿函数的例 struct plus{ int operator()(const int& x, const int&am

SGI STL functors(仿函数) 12

函数对象,即"行为类似函数"的对象,重载function call运算子(operator ()).STL仿函数根据操作数个数划分,可分为一元和二元仿函数,按功能划分可分为算数运算.关系运算.逻辑运算三大类.使用内建仿函数需包含<functional>头文件. 仿函数可配接的关键 为了拥有配接能力,需要依照规定定义自己的5个相应型别.仿函数的相应型别主要用来表现函数参数型别和传回值型别.为了方便期间,<stl_function.h>定义了两个class,分别表示

STL函数对象和Lambda表达式

1.基本概念 Function object是定义了operator()的object. FunctionObjectType fo; fo(…);调用函数对象的operator()代替函数fo()的调用. 等价于:fo.operator()(…); 函数对象的三个好处: (1) 函数对象可以有自己的状态,因此可能是更聪明的.你可以拥有同一个函数对象的两个实例,它们可能有不同的状态. (2) 每个函数对象是一个类型.你可以把函数对象作为模版的参数用于指定一个特定的行为. (3)函数对象通常比函数

STL标准库-仿函数

摘要: 摘要: 摘要: 技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 仿函数的实现:声明一个类,重载它的operator call ("()"操作符) template<typename T> class lineFeed { public: void operator()(const T &x) { cout<<x<<endl; } }; 仿函数只为算法服务,但是像上面这种声明方式,虽然在有些时候可以使用,但是却不

STL——临时对象的产生与运用

所谓临时对象,就是一种无名对象.它的出现如果不在程序员的预期之下(例如任何pass by value操作都会引发copy操作,于是形成一个临时对象),往往造成效率上的负担.但有时候刻意制造一些临时对象,却又是使程序干净清爽的技巧.刻意制造临时对象的方法是,在型别名称之后直接加一对小括号,并可指定初值,例如Shape(3,5)或int(8),其意义相当于调用相应的constructor且不指定对象名称.STL最常将此技巧应用于仿函数(functor)与算法的搭配上,例如: #include<ios

函数对象(仿函数 functor)

简单地说,函数对象就是一个重载了()运算符的类实例,它可以像一个函数一样使用. #include <iostream> using namespace std; class Add { public: int operator ()(const int &a, const int &b) { return (a + b); } double operator ()(const double &a, const double &b) { return (a + b

STL 函数对象

一.函数对象? 若一个类重载了运算符 “()”,则该类的对象就成为函数对象 1 class CMyAverage { //函数对象类 2 public: 3 double operator() ( int a1, int a2, int a3 ) { 4 return (double)(a1 + a2+a3) / 3; 5 } 6 }; 7 CMyAverage average; //函数对象 8 cout << average(3,2,3); // average.operator()(3,

STL源码剖析——STL函数对象

前言 在STL中,函数对象也是比较重要的,有时候可以限定STL算法的行为,例如在前面介绍的<STL算法剖析>中,每个算法基本上都提供了两个操作版本,其中就用一个版本允许用户指定函数对象,这样可以根据用户的需要对算法进行操作.函数对象是一种具有函数特质的对象,所以可以作为算法的参数.本文介绍的函数对象比较简单,是基于一元或者二元操作结构的算术类函数对象.关系运算类函数对象.逻辑运算类函数对象.在定义函数对象时,为了使其具有函数行为,则必须重载operator()操作符.本文源码出自SGI STL