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

Posted chengonghao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.
*
*  chengonghao@yeah.net
*
*  文件内容:算术类(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.
*
*  chengonghao@yeah.net
*
*  文件内容:函数对象的实现
******************************************************************/

#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.
*
*  chengonghao@yeah.net
*
*  文件内容:测试算术类(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.
*
*  chengonghao@yeah.net
*
*  文件内容:测试关系运算类(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.
*
*  chengonghao@yeah.net
*
*  文件内容:测试逻辑运算类(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;
}


测试结果:


以上是关于STL简单函数对象(仿函数)的实现的主要内容,如果未能解决你的问题,请参考以下文章

STL——容器(Set & multiset)之 仿函数(函数对象)functor 的用法

STL——容器(Set & multiset)之 仿函数(函数对象)functor 的用法

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

STL 简介

STL基础--仿函数(函数对象)

SGI STL functors(仿函数) 12