本文參考文獻::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參數傳遞
執行速度,仿函數比函數指針更快。