本文参考文献::GeekBand课堂内容,授课老师:张文杰ios
:C++ Primer 11 中文版(第五版) page 37算法
:网络资料: 叶卡同窗的部落格 http://www.leavesite.com/数组
前言:本文主要经过关联容器set解释下仿函数的实现及工做原理。网络
一、Containers(容器):各类数据结构,如Vector,List,Deque,Set,Map,用来存放数据
二、Algorithms(算法):如、 Sort,Search。
三、Iterators(迭代器):扮演容器与算法之间的胶合剂,是所谓的“泛型指针”,
四、Functors(仿函数): 行为相似函数,可做为算法的某种策略(Policy
五、Adapters(配接器、适配器):一种用来修饰容器(Containers)或仿函数(Functors)或迭代器(Iterators)接口的东西,
六、Allocators(分配器):负责空间配置与管理数据结构
具体的关系如图,之后会更新各个组件的关系,本文重点关注下仿函数相关知识要点函数
一、函数指针,就是一个指针,它指向一个函数。运用时至关于回调了这个函数。spa
示例以下:.net
这里经过fp指针,指向了PrintTest函数,这里 fp();就是调用 PrintTest函数,打印了Hello World 指针
其实仿函数就相似于函数指针的使用。下面会经过例子来讲明。code
#include "stdafx.h" typedef void(*Test)(char* s); void printTest(char* s); int main(int argc, char* argv[]) { Test fp; //一般是用宏Test来声明一个函数指针fp fp = printTest; fp("Hello World!\n"); return 0; } void printTest(char* src) { printf(src); }
结果以下:
再看一遍仿函数的定义:
Functors(仿函数):something that performs a function, 即相似函数的东西,那么它是什么样子的,又是如何实现的呢?
使用仿函数可使迭代和计算分离开来。于是你的functor能够应用于不一样场合,在STL的算法中就大量使用了functor
set<Programmer, ProgrammerIdGreater> set1(programmerArray, programmerArray + 6); cout << "Traversal And Sort The Programmer by Number " << endl; //print for_each(set1.begin(), set1.end(), mem_fn(&Programmer::Print)); cout << "\n" << endl;
这里经过set容器,经过 <>来进行了自定义的比较操做,这里其实是经过适配器调用了重载了仿函数()运算符
下一句for_each这句就更明显了!这里经过类中重载()运算符的方法使用了一个函数对象
就是一个类看上去是一个函数,其实现方法就是类中重载了一个operator(),这个类就有了相似函数的行为,就是一个仿函数类了
//仿函数(理解为函数指针),对()进行重载,就是一旦用括号了,括号内的内容已经排序完毕 //咱们若是要让仿函数支持适配器,那么就必须从binary_function派生出来。 struct ProgrammerIdGreater : public binary_function<Programmer, Programmer, bool> { bool operator() (const Programmer& PosFront, const Programmer& PosBehind) const { //降序排列 //return (PosFront.GetId() <= PosBehind.GetId()) ? false : true; //升序排列 return (PosFront.GetId() < PosBehind.GetId()) ? true : false; } }; //一元的都继承自unary_function,二元则继承自binary_function, 由于继承自这两个函数的仿函数均定义了相应型别供 //配接时使用,也就具备了配接能力。 /* template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; */ struct ProgrammerNameComparer : public binary_function<Programmer, Programmer, bool> { bool operator() (const Programmer& PosFront, const Programmer& PosBehind) const { //按照名称降序排列 //return (PosFront.GetName() <= PosBehind.GetName()) ? false : true; //按照名称升序排列 return (PosFront.GetName() <= PosBehind.GetName()) ? true : false; } };
// Programmer.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "programmer.h" #include <iostream> #include <set> #include <algorithm> #include <functional> using namespace std; /* set的iterator类型通常是const的引用类型,所以当set保存的是类类型时,对iterator解引用没法调用类的非const成员。 解决办法:1.set中不存储对象自己,改成存储对象指针 利用const_cast<Programmer&> 进行转型 */ int main(int argc, char** argv) { const Programmer programmerArray[6] = { Programmer(1, L"Scott Meyers"), Programmer(2, L"Martin Fowler"), Programmer(3, L"Bill Gates"), Programmer(4, L"P.J. Plaught"), Programmer(5, L"Stanley B. Lippman"), Programmer(6, L"Andrei Alexandrescu"), }; //仿函数ProgrammerIdGreater排序,此时重载了小括号 //以序列号进行排序 set<Programmer, ProgrammerIdGreater> set1(programmerArray, programmerArray + 6); cout << "Traversal And Sort The Programmer by Number " << endl; //print for_each(set1.begin(), set1.end(), mem_fn(&Programmer::Print)); cout << "\n" << endl; //查找目标,并将目标修改成David Vandevoorde set<Programmer, ProgrammerIdGreater>::iterator it = set1.find(Programmer(3, L"Bill Gates")); if (it != set1.end()) { const_cast<Programmer&>(*it).SetName(L"David Vandevoorde"); } cout << "Change The Name Of Third Element And Traversal" << endl; //print for_each(set1.begin(), set1.end(), mem_fn(&Programmer::Print)); cout << "\n" << endl; //此时并无保存到数组programmerArray[6]中 //按照名称进行排序 cout << "Traversal And Sort The Programmer by Name " << endl; set<Programmer, ProgrammerNameComparer> set2(set1.begin(), set1.end()); //print for_each(set2.begin(), set2.end(), mem_fn(&Programmer::Print)); return 0; }
#ifndef __PROGRAMMER_H__ #define __PROGRAMMER_H__ #include <iostream> #include <string> using namespace std; struct Programmer { public: //构造函数 Programmer(const int id, const wstring name) : Id(id), Name(name) { } void Print() const { wcout << L"[" << Id << L"]:" << Name << endl; } const int GetId() const { return Id; } const wstring& GetName() const { return Name; } void SetName(const wstring& name) { Name = name; } private: int Id; wstring Name; }; //仿函数(理解为函数指针),对()进行重载,就是一旦用括号了,括号内的内容已经排序完毕 //咱们若是要让仿函数支持适配器,那么就必须从binary_function派生出来。 struct ProgrammerIdGreater : public binary_function<Programmer, Programmer, bool> { bool operator() (const Programmer& PosFront, const Programmer& PosBehind) const { //降序排列 //return (PosFront.GetId() <= PosBehind.GetId()) ? false : true; //升序排列 return (PosFront.GetId() < PosBehind.GetId()) ? true : false; } }; //一元的都继承自unary_function,二元则继承自binary_function, 由于继承自这两个函数的仿函数均定义了相应型别供 //配接时使用,也就具备了配接能力。 /* template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; */ struct ProgrammerNameComparer : public binary_function<Programmer, Programmer, bool> { bool operator() (const Programmer& PosFront, const Programmer& PosBehind) const { //按照名称降序排列 //return (PosFront.GetName() <= PosBehind.GetName()) ? false : true; //按照名称升序排列 return (PosFront.GetName() <= PosBehind.GetName()) ? true : false; } }; #endif
关于Set容器的使用请参考。非在本文讨论范围内。
http://blog.csdn.net/lyhvoyage/article/details/22989659
仿函数相似函数指针,经过这样对比来记忆。
仿函数要重载operator()
仿函数都有其型别。所以他能够将仿函数的型别当template参数传递
执行速度,仿函数比函数指针更快。