從零開始學C++之STL(八):函數對象、 函數對象與容器、函數對象與算法

http://blog.csdn.net/jnu_simba/article/details/9500219

一、函數對象

1、函數對象(function object)也稱為仿函數(functor)


2、一個行為類似函數的對象,它可以沒有參數,也可以帶有若干參數。


3、任何重載了調用運算符operator()的類的對象都滿足函數對象的特征


4、函數對象可以把它稱之為smart function。


5、STL中也定義了一些標準的函數對象,如果以功能劃分,可以分為算術運算、關系運算、邏輯運算三大類。為了調用這些標準函數對象,需要包含頭文件<functional>。


二、自定義函數對象

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include?<iostream>
using?namespace?std;
class?CFunObj
{
public:
????void?operator()()
????{
????????cout?<<?"hello,function?object!"?<<?endl;
????}
};
int?main()
{
????CFunObj?fo;
????fo();
????CFunObj()();
????return?0;
}

注意:CFunObj()(); 表示先構造一個匿名對象,再調用operator();


三、函數對象與容器


在這邊舉map 容器的例子,大家都知道map 在插入元素的時候會自動排序,默認是根據key 從小到大排序,看map 的定義:

C++ Code?
1
2
3
4
5
6
7
8
9
10
//?TEMPLATE?CLASS?map
template?<?class?_Kty,
?????????class?_Ty,
?????????class?_Pr?=?less<_Kty>,
?????????class?_Alloc?=?allocator<pair<const?_Kty,?_Ty>?>?>
class?map
????:?public?_Tree<_Tmap_traits<_Kty,?_Ty,?_Pr,?_Alloc,?false>?>
{
????//?ordered?red-black?tree?of?{key,?mapped}?values,?unique?keys
};

假設現在我們這樣使用 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?
1
2
3
4
5
6
7
8
9
10
11
12
13
//?TEMPLATE?STRUCT?less
template<class?_Ty>
struct?less
????????:?public?binary_function<_Ty,?_Ty,?bool>
{
????//?functor?for?operator<
????bool?operator()(const?_Ty?&_Left,?const?_Ty?&_Right)?const
????{
????????//?apply?operator<?to?operands
????????return?(_Left?<?_Right);
????}
};

即實現了operator() 函數,左操作數小于右操作數時返回為真。


我們也可以在定義的時候傳遞第三個參數,如map< int, string, greater<int> > mapTest; 則插入時按key 值從大到小排序(less,


?greater 都是STL內置的類,里面實現了operator() 函數),甚至也可以自己實現一個類傳遞進去,如下面例程所示:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include?<map>
#include?<string>
#include?<iostream>

using?namespace?std;

struct?MyGreater
{
????bool?operator()(int?left,?int?right)
????{
????????return?left?>?right;
????}
};

int?main(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_iterator?it?=?mapTest.begin();?it?!=?mapTest.end();?++it)
????{
????????cout?<<?it->first?<<?"?"?<<?it->second?<<?endl;
????}

????return?0;
}

輸出為:

3 cccc

2 bbbb

1 aaaa


MyGreater 類并不是以模板實現,只是比較key 值為int 類型的大小。


四、函數對象與算法

在STL一些算法中可以傳入函數指針,實現自定義比較邏輯或者計算,同樣地這些函數也可以使用函數對象來代替,直接看例程再稍

作分析:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include?<vector>
#include?<string>
#include?<iostream>
#include?<algorithm>

using?namespace?std;

void?PrintFun(int?n)
{
????cout?<<?n?<<?'?';
}

void?Add3(int?&n)
{
????n?+=?3;
}

class?PrintObj
{
public:
????void?operator()(int?n)
????{
????????cout?<<?n?<<?'?';
????}
};

class?AddObj
{
public:
????AddObj(int?number)?:?number_(number)
????{

????}
????void?operator()(int?&n)
????{
????????n?+=?number_;
????}

private:
????int?number_;
};

class?GreaterObj
{
public:
????GreaterObj(int?number)?:?number_(number)
????{

????}
????bool?operator()(int?n)
????{
????????return?n?>?number_;
????}
private:
????int?number_;
};


int?main(void)
{
????int?a[]?=?{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的元素個數

????return?0;
}

輸出為:

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++編程規范


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384213.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384213.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384213.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

樹狀數組初步理解

學習樹狀數組已經兩周了&#xff0c;之前偷懶一直沒有寫&#xff0c;趕緊補上防止自己忘記&#xff08;雖然好像已經忘得差不多了&#xff09;。 作為一種經常處理區間問題的數據結構&#xff0c;它和線段樹、分塊一樣&#xff0c;核心就是將區間分成許多個小區間然后通過對大區…

命名函數

函數體是代碼塊 代碼塊do...end是一種表達式的組織方式。 # ./times.exs下defmodule Times dodef doule(n) don * 2end end 函數調用與模式匹配 代碼如下&#xff1a; # ./factorial.exs    計算階層 defmodule Factorial dodef of(0), do: 1          #終止條件…

STL運用的C++技術(6)——函數對象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t0.20427969420870595 STL是C標準庫的重要組成部分之一&#xff0c;它不僅是一個可復用的組件庫&#xff0c;更是一個包含算法與數據結構的軟件框架&#xff0c;同時也是C泛型編程的很好例子。STL中運用了許多…

列表與遞歸

頭部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #報錯 創建映射函數 我們可以使用一個函數來處理列表中的各個元素&#xff0c;如此可以接受更加復雜的處理&#xff0c;也可以…

優先隊列小結

不像棧和隊列&#xff0c;雖然STL有較好實現但是我們自己也可以很方便的實現&#xff0c;優先隊列自己實現起來就比較復雜&#xff0c;比較浪費時間&#xff08;而且自己目前也不會233&#xff09;而優先隊列因為其較好的特性經常被使用&#xff0c;因此對它的熟練掌握是做題的…

字典:散列表、散列字典、關鍵字列表、集合與結構體

字典 散列表和散列字典都實現了Dict的行為。Keyword模塊也基本實現了&#xff0c;不同之處在于它支持重復鍵。 Eunm.into可以將一種類型的收集映射轉化成另一種。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 學習筆記 lambda表達式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表達式是C11最重要也最常用的一個特性之一。lambda來源于函數式編程的概念&#xff0c;也是現代編程語言的一個特點。 一.函數式編程簡介 定義&#xff1a;簡單說&#xff0c;“函數式編程”是一種“編程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常見用法見&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort時&#xff0c;如果要獲得穩定的排序結果&#xff0c;要使用< 而不是 <。 Stream Stream是延遲處理的&#xff0c;而Enum是貪婪的&#xff0c;則意味著傳給它一個收集&#xff…

linux網絡編程之posix 線程(三):posix 匿名信號量與互斥鎖 示例生產者--消費者問題

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信號量 信號量的概念參見這里。前面也講過system v 信號量&#xff0c;現在來說說posix 信號量。 system v 信號量只能用于進程間同步&#xff0c;而posix 信號量除了可以進程間同步&#xff0c;還可以線程間…

洛谷P1080-國王游戲-貪心+高精度

P1080-國王游戲 啊啊啊&#xff0c;剛才已經寫了一次了&#xff0c;但是Edge瀏覽器不知道為什么卡住了&#xff0c;難受。 好吧&#xff0c;其實是一道可做題&#xff0c;分析得到的貪心策略就是就是將a * b小的放在前面&#xff08;其他的懶得說了&#xff09;&#xff0c;主要…

字符串與二進制

單引號字符串會被表示成整數值列表。 &#xff1f;c返回字符 c 的整數編碼。下面這個例子用于解析字符列表表示法&#xff0c;該表示法用于表示一個任意的有符號的十進制數據。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092蟲食算-深度優先搜索+玄學剪枝

P1092蟲食算 這道題的思想并不復雜&#xff0c;可是難點在于各種玄學剪枝。在仔細研究了題解大佬的剪枝原理后終于氵了過去。 先上代碼&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多進程

使用spawn創建一個新進程&#xff0c;其第一個參數是模塊名、第二個參數是函數名、第三個參數是參數列表。spawn會返回一個進程標識符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket編程(二) 服務器與客戶端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇寫了對套接字操作的封裝&#xff0c;這一節使用已封裝好的Socket類實現服務器與客戶端的通信&#xff08;Socket的定義見上篇Socket.h) 服務器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服務器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告訴OTP將第二個元素返回給客戶端end end use的效果將OTP GenServer的行為添加到當前模塊。這樣它就可以處理所有…

洛谷P1040-加分二叉樹-dp+二叉樹

P1040-加分二叉樹 這道題放在深度優先搜索的訓練題中&#xff0c;可是我實在沒有看出來應該怎么搜索。看了題解以后才看出來是一個很簡單的dp(我果然還是太菜了) 看出dp并且算出來最大的分數不是很復雜&#xff0c;關鍵是輸出給定中序遍歷序列的二叉樹的先序遍歷&#xff0c;要…

UNIX網絡編程:I/O復用技術(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五種&#xff1a;阻塞I/O 、非阻塞I/O 、I/O復用 、信號驅動I/O 、異步I/O。此處我們主要介紹第三種I/O符復用。 I/O復用的功能&#xff1a;如果一個或多個I/O條件滿足&#xff08;輸…

解決iex -S mix報錯

執行iex -S mix命令的時候會遇到如下錯誤&#xff1a; 執行 mix deps.get 然后就可以運行 iex -S mix了 其中&#xff0c;有可能會出現 按照其網站下載相應文件&#xff0c;復制到項目根目錄下&#xff0c;然后執行命令&#xff08;mix local.rebar rebar ./rebar&#xff09;即…

貪心算法——選擇不相交區間問題

題目描述&#xff1a;設有n個活動的集合&#xff0c;其中每個活動都要求使用同一個資源&#xff0c;而在同一時間內只有一個活動能夠使用這一資源&#xff0c;每個活動i都有一個要求使用該資源的起始時間si和一個結束時間fi(si<fi)&#xff0c;如果選擇了活動i&#xff0c;則…