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 的用法