一、函数对象
1、函数对象(function object)也称为仿函数(functor)
2、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。
3、任何重载了调用运算符operator()的类的对象都满足函数对象的特征
4、函数对象可以把它称之为smart function。
5、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。
二、自定义函数对象
C++ Code
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br></nobr>
|
|
#include<iostream> usingnamespacestd; classCFunObj
{ public: voidoperator()()
{
cout<<"hello,functionobject!"<<endl;
}
}; intmain()
{
CFunObjfo;
fo();
CFunObj()(); return0;
}
|
注意:CFunObj()(); 表示先构造一个匿名对象,再调用operator();
三、函数对象与容器
在这边举map 容器的例子,大家都知道map 在插入元素的时候会自动排序,默认是根据key 从小到大排序,看map 的定义:
C++ Code
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br></nobr>
|
|
//TEMPLATECLASSmap template<class_Kty, class_Ty, class_Pr=less<_Kty>, class_Alloc=allocator<pair<const_Kty,_Ty>>> classmap
:public_Tree<_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>
{ //orderedred-blacktreeof{key,mapped}values,uniquekeys };
|
假设现在我们这样使用 map< int, string > mapTest; 那么默认的第三个参数 _Pr = less<int>,再者,map 继承的其中一个类
_Tmap_traits 中有个成员:
_Pr comp;// the comparator predicate for keys
跟踪进insert 函数,其中有这样一句:
if (_DEBUG_LT_PRED(this->comp,_Key(_Where._Mynode()), this->_Kfn(_Val)))
已知#define _DEBUG_LT_PRED(pred, x, y) pred(x, y) 很明显地,comp 在这里当作函数对象使用,传入两个参数,回头看less 类的
模板实现:
C++ Code
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br></nobr>
|
|
//TEMPLATESTRUCTless template<class_Ty> structless
:publicbinary_function<_Ty,_Ty,bool>
{ //functorforoperator< booloperator()(const_Ty&_Left,const_Ty&_Right)const
{ //applyoperator<tooperands return(_Left<_Right);
}
};
|
即实现了operator() 函数,左操作数小于右操作数时返回为真。
我们也可以在定义的时候传递第三个参数,如map< int, string, greater<int> > mapTest; 则插入时按key 值从大到小排序(less,
greater 都是STL内置的类,里面实现了operator() 函数),甚至也可以自己实现一个类传递进去,如下面例程所示:
C++ Code
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br></nobr>
|
|
#include<map> #include<string> #include<iostream>
usingnamespacestd;
structMyGreater
{ booloperator()(intleft,intright)
{ returnleft>right;
}
};
intmain(void)
{
map<int,string,/*greater<int>*/MyGreater>mapTest;
mapTest.insert(map<int,string>::value_type(1,"aaaa"));
mapTest.insert(map<int,string>::value_type(3,"cccc"));
mapTest.insert(map<int,string>::value_type(2,"bbbb"));
for(map<int,string,/*greater<int>*/MyGreater>::const_iteratorit=mapTest.begin();it!=mapTest.end();++it)
{
cout<<it->first<<""<<it->second<<endl;
}
return0;
}
|
输出为:
3 cccc
2 bbbb
1 aaaa
MyGreater 类并不是以模板实现,只是比较key 值为int 类型的大小。
四、函数对象与算法
在STL一些算法中可以传入函数指针,实现自定义比较逻辑或者计算,同样地这些函数也可以使用函数对象来代替,直接看例程再稍
作分析:
C++ Code
<nobr>1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
8<br>
9<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
31<br>
32<br>
33<br>
34<br>
35<br>
36<br>
37<br>
38<br>
39<br>
40<br>
41<br>
42<br>
43<br>
44<br>
45<br>
46<br>
47<br>
48<br>
49<br>
50<br>
51<br>
52<br>
53<br>
54<br>
55<br>
56<br>
57<br>
58<br>
59<br>
60<br>
61<br>
62<br>
63<br>
64<br>
65<br>
66<br>
67<br>
68<br>
69<br>
70<br>
71<br>
72<br>
73<br>
74<br>
75<br>
76<br>
77<br>
78<br>
79<br>
80<br>
81<br>
82<br></nobr>
|
|
#include<vector> #include<string> #include<iostream> #include<algorithm>
usingnamespacestd;
voidPrintFun(intn)
{
cout<<n<<'';
}
voidAdd3(int&n)
{
n+=3;
}
classPrintObj
{ public: voidoperator()(intn)
{
cout<<n<<'';
}
};
classAddObj
{ public:
AddObj(intnumber):number_(number)
{
} voidoperator()(int&n)
{
n+=number_;
}
private: intnumber_;
};
classGreaterObj
{ public:
GreaterObj(intnumber):number_(number)
{
} booloperator()(intn)
{ returnn>number_;
} private: intnumber_;
};
intmain(void)
{ inta[]={1,2,3,4,5};
vector<int>v(a,a+5);
/*for_each(v.begin(),v.end(),PrintFun);
cout<<endl;*/
for_each(v.begin(),v.end(),PrintObj());
cout<<endl;
/*for_each(v.begin(),v.end(),Add3);
for_each(v.begin(),v.end(),PrintFun);
cout<<endl;*/
for_each(v.begin(),v.end(),AddObj(5));
for_each(v.begin(),v.end(),PrintFun);
cout<<endl;
cout<<count_if(a,a+5,GreaterObj(3))<<endl;//计算大于3的元素个数
return0;
}
|
输出为:
1 2 3 4 5
6 7 8 9 10
2
回顾for_each 的源码,其中有这样一句:_Func(*_ChkFirst); 也就是将遍历得到的元素当作参数传入函数。
上面程序使用了函数对象,实际上可以这样理解PrintObj()(*_ChkFirst);
即PrintObj() 是一个匿名的函数对象,传入参
数,调用了operator()
函数进行打印输出。使用函数对象的好处是比较灵活,比如直接使用函数Add3,那么只能将元素加3,而
使用函数对象Addobj(x),
想让元素加上多少就传递给Addobj类,构造一个对象即可,因为它可以保存一种状态(类成员)。
count_if 中的 GreaterObj(3) 就类似了,将遍历的元素当作参数传递给operator(), 即若元素比3大则返回为真。
五、STL内置的函数对象类
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
分享到:
相关推荐
C++库函数及STL算法(英文版)介绍及用法 每个函数都有简单的源文件说明,有例子
c++ STL, stl,stl的学习c++ STL, stl,stl的学习c++ STL, stl,stl的学习c++ STL, stl,stl的学习
STL容器和算法函数表. 玩C++清一定看看STL
该篇分为十一部分,分别是:vector类的主要成员...stack类的主要成员、queue类的主要成员、priority_queue类的组要成员、set类的主要成员、multiset类的主要成员、map类的主要成员、multimap类的主要成员、STL算法函数
C++ stl算法汇总 STL 各种算法 应用 大全
stl常用算法,模板stl常用算法,
C++STL容器总结笔记自用学算法必学
C++ STL std的string详细讲解
很全的STL string类的函数方法,便于查询
后端 / C++ 类 封装 继承 多态 stl容器 虚函数 纯虚函数 友元函数 模板
Mastering the C++17 STL: Make full use of the standard library components in C++17 C__17 STL Cookbook.epub C__17 STL Cookbook.mobi C__17 STL Cookbook.pdf 9781787120495_Code.zip Mastering the C++17...
包含常用stl string的常用函数
C++ STL参考相当全面, 而且例子也很好. 为chm格式, 彩色, 目录和索引链接找东西很方便,还包含大量常用函数,且按函数名首字母排序,方便查找 也有 C 的函数速查手册哦!!
C++模拟实现的类似于C#的委托。 使用STL封装类名称的变化,使用函数指针封装函数名称的变化。 在Visual C++ 6.0下测试通过。 使用的时候只需要关注IFunctor和IDelegate两个接口即可。
关于stl的一些用法 STL算法作为模板函数提供 STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。
C++ STL--数据结构与算法实现(余文溪)示例程序代码.rar
详细介绍了有关C++ STL的常用函数,接口等基本知识。 确实对编程有很大帮助
从逆向角度看C++ STL代码之std::map
STL有三大核心部分:容器(Container)、算法(Algorithms)、迭代器(Iterator),容器适配器(container adaptor),函数对象(functor),除此之外还有STL其他标准组件。
下面是对SGI STL源码的一些关键特点和描述:泛型编程、算法与容器的分离、迭代器、函数对象等。 SGI STL的源码是学习和理解STL实现原理的宝贵资源。它展示了如何使用C++的语言特性和编程技巧来设计和实现高效、灵活...