(原創) Function Pointer、Delegate和Function Object (C/C++) (template) (.NET) (C#)

原文地址为: (原創) Function Pointer、Delegate和Function Object (C/C++) (template) (.NET) (C#)

Abstract
Function Pointer(C)、Delegate(C#)和Function Object(C++)這三個其實是一樣的功能,所以在此一併討論。

Introduction
function pointer是C語言中最高級的機制,大概很多人還沒上到這裡已經學期末了,所以不少C語言工程師根本不知道C語言有function pointer;而C#的delegate大抵跟C語言的function pointer功能相同,所以很多書說delegate是物件導向的function pointer;C++的function object功能則比function pointer略強,還可配合泛型使用。

為什麼會需要function pointer、delegate、function object這種機制呢?源於一個很簡單的想法:『為什麼我們不能將function也如同變數一樣傳進另外一個function呢?』,C語言的解決方式是,利用pointer指向該function,將該pointer傳入另外一個function,只要將該pointer dereference後,就如同存取原function一樣。C#解決的方式是,將function包成delegate object,傳入另外一個function。C++的解決方式是,利用class或struct將function包成object,傳入另外一個function。

一個很簡單的需求,想個別列出陣列中,所有奇數、偶數、和大於2的數字,若使用傳統方式,而不使用function pointer,則寫法如下

 1 731655954c7be9d8835ece551b5385f8.jpe #include  < iostream >
 2 731655954c7be9d8835ece551b5385f8.jpe
 3 731655954c7be9d8835ece551b5385f8.jpe using   namespace  std;
 4 731655954c7be9d8835ece551b5385f8.jpe
 5 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe void  printArrayOdd( int *  beg,  int *  end)  222530190136c9c4cfd237cc0d5cff99.jpe {
 6715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  while(beg != end) 222530190136c9c4cfd237cc0d5cff99.jpe{
 71408c5260b2f05e450dee929db9be5f7.jpe    if ((*beg)%2)
 81408c5260b2f05e450dee929db9be5f7.jpe      cout << *beg << endl;
 91408c5260b2f05e450dee929db9be5f7.jpe      
101408c5260b2f05e450dee929db9be5f7.jpe    beg++;
115bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

12f466905a3bcb5dcef110eab799825254.jpe}

13 731655954c7be9d8835ece551b5385f8.jpe
14 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe void  printArrayEven( int *  beg,  int *  end)  222530190136c9c4cfd237cc0d5cff99.jpe {
15715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  while(beg != end) 222530190136c9c4cfd237cc0d5cff99.jpe{
161408c5260b2f05e450dee929db9be5f7.jpe    if (!((*beg)%2))
171408c5260b2f05e450dee929db9be5f7.jpe      cout << *beg << endl;
181408c5260b2f05e450dee929db9be5f7.jpe      
191408c5260b2f05e450dee929db9be5f7.jpe    beg++;
205bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

21f466905a3bcb5dcef110eab799825254.jpe}

22 731655954c7be9d8835ece551b5385f8.jpe
23 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe void  printArrayGreaterThan2( int *  beg,  int *  end)  222530190136c9c4cfd237cc0d5cff99.jpe {
24715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  while(beg != end) 222530190136c9c4cfd237cc0d5cff99.jpe{
251408c5260b2f05e450dee929db9be5f7.jpe    if ((*beg)>2)
261408c5260b2f05e450dee929db9be5f7.jpe      cout << *beg << endl;
271408c5260b2f05e450dee929db9be5f7.jpe      
281408c5260b2f05e450dee929db9be5f7.jpe    beg++;
295bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

30f466905a3bcb5dcef110eab799825254.jpe}

31 731655954c7be9d8835ece551b5385f8.jpe
32 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe int  main()  222530190136c9c4cfd237cc0d5cff99.jpe {
33715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  int ia[] = 222530190136c9c4cfd237cc0d5cff99.jpe{123};
341408c5260b2f05e450dee929db9be5f7.jpe  
351408c5260b2f05e450dee929db9be5f7.jpe  cout << "Odd222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
361408c5260b2f05e450dee929db9be5f7.jpe  printArrayOdd(ia, ia + 3);
371408c5260b2f05e450dee929db9be5f7.jpe
381408c5260b2f05e450dee929db9be5f7.jpe  
391408c5260b2f05e450dee929db9be5f7.jpe  cout << "Even222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
401408c5260b2f05e450dee929db9be5f7.jpe  printArrayEven(ia, ia + 3);
411408c5260b2f05e450dee929db9be5f7.jpe  
421408c5260b2f05e450dee929db9be5f7.jpe  cout << "Greater than 2222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
431408c5260b2f05e450dee929db9be5f7.jpe  printArrayGreaterThan2(ia, ia + 3);
44f466905a3bcb5dcef110eab799825254.jpe}


執行結果

731655954c7be9d8835ece551b5385f8.jpe Odd222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
1
731655954c7be9d8835ece551b5385f8.jpe
3
731655954c7be9d8835ece551b5385f8.jpeEven222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
2
731655954c7be9d8835ece551b5385f8.jpeGreater than 
2 222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
3


以功能而言沒有問題,但每個function都要做迴圈與判斷,似乎重覆了,而且將來若有新的判斷,又要copy整個迴圈,然後改掉判斷式,若能將迴圈與判斷式分離,若日後有新的判斷式,只要將該判斷式傳進來即可,這就是function pointer概念。

使用C語言的Function Pointer

 1 24a924a57ba6b3f2b51fc9edb7ea4186.jpe 9310e85a14af99de4811ff4c77f1f911.jpe /**/ /* 
 21408c5260b2f05e450dee929db9be5f7.jpe(C) OOMusou 2007 http://oomusou.cnblogs.com
 31408c5260b2f05e450dee929db9be5f7.jpe
 41408c5260b2f05e450dee929db9be5f7.jpeFilename    : FuntionPointer.cpp
 51408c5260b2f05e450dee929db9be5f7.jpeCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 61408c5260b2f05e450dee929db9be5f7.jpeDescription : Demo how to use function pointer
 71408c5260b2f05e450dee929db9be5f7.jpeRelease     : 05/01/2007 1.0
 8f466905a3bcb5dcef110eab799825254.jpe*/

 9 731655954c7be9d8835ece551b5385f8.jpe#include  < iostream >
10 731655954c7be9d8835ece551b5385f8.jpe
11 731655954c7be9d8835ece551b5385f8.jpe using   namespace  std;
12 731655954c7be9d8835ece551b5385f8.jpe
13 731655954c7be9d8835ece551b5385f8.jpetypedef  bool  ( * predicate)( int );
14 731655954c7be9d8835ece551b5385f8.jpe
15 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe bool  isOdd( int  i)  222530190136c9c4cfd237cc0d5cff99.jpe {
161408c5260b2f05e450dee929db9be5f7.jpe  return i%2? true : false;
17f466905a3bcb5dcef110eab799825254.jpe}

18 731655954c7be9d8835ece551b5385f8.jpe
19 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe bool  isEven( int  i)  222530190136c9c4cfd237cc0d5cff99.jpe {
201408c5260b2f05e450dee929db9be5f7.jpe  return i%2? false : true;
21f466905a3bcb5dcef110eab799825254.jpe}

22 731655954c7be9d8835ece551b5385f8.jpe
23 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe bool  greaterThan2( int  i)  222530190136c9c4cfd237cc0d5cff99.jpe {
241408c5260b2f05e450dee929db9be5f7.jpe  return i > 2;
25f466905a3bcb5dcef110eab799825254.jpe}

26 731655954c7be9d8835ece551b5385f8.jpe
27 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe void  printArray( int *  beg,  int *  end, predicate fn)  222530190136c9c4cfd237cc0d5cff99.jpe {
28715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  while(beg != end) 222530190136c9c4cfd237cc0d5cff99.jpe{
291408c5260b2f05e450dee929db9be5f7.jpe    if ((*fn)(*beg))
301408c5260b2f05e450dee929db9be5f7.jpe      cout << *beg << endl;
311408c5260b2f05e450dee929db9be5f7.jpe      
321408c5260b2f05e450dee929db9be5f7.jpe    beg++;
335bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

34f466905a3bcb5dcef110eab799825254.jpe}

35 731655954c7be9d8835ece551b5385f8.jpe
36 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe int  main()  222530190136c9c4cfd237cc0d5cff99.jpe {
37715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  int ia[] = 222530190136c9c4cfd237cc0d5cff99.jpe{123};
381408c5260b2f05e450dee929db9be5f7.jpe  
391408c5260b2f05e450dee929db9be5f7.jpe  cout << "Odd222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
401408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, isOdd);
411408c5260b2f05e450dee929db9be5f7.jpe  
421408c5260b2f05e450dee929db9be5f7.jpe  cout << "Even222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
431408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, isEven);
441408c5260b2f05e450dee929db9be5f7.jpe  
451408c5260b2f05e450dee929db9be5f7.jpe  cout << "Greater than 2222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
461408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, greaterThan2);
47f466905a3bcb5dcef110eab799825254.jpe}


執行結果

731655954c7be9d8835ece551b5385f8.jpe Odd222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
1
731655954c7be9d8835ece551b5385f8.jpe
3
731655954c7be9d8835ece551b5385f8.jpeEven222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
2
731655954c7be9d8835ece551b5385f8.jpeGreater than 
2 222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
3


第13行

731655954c7be9d8835ece551b5385f8.jpe typedef  bool  ( * predicate)( int );


宣告了predicate這個function ponter型別,指向回傳值為bool,參數為int的function,值得注意的是(*predicate)一定要括號刮起來,否則compiler會以為是bool*,我承認這個語法很奇怪,但若仔細想想,若我是C語言發明者,我應該也是這樣定語法,因為也沒其他更好的語法了:D。

這個範例將判斷式和迴圈分開,日後若有新的判斷式,只要新增判斷式即可,funtion pointer提供了一個型別,讓參數可以宣告function pointer型別

24a924a57ba6b3f2b51fc9edb7ea4186.jpe 9310e85a14af99de4811ff4c77f1f911.jpe void  printArray( int *  beg,  int *  end, predicate fn)  222530190136c9c4cfd237cc0d5cff99.jpe {


如此我們就可以將function傳進另外一個fuction了。

使用C#的Delegate
C#是個物件導向的語言,為了提供類似function pointer的機制,提出了delegate概念,delegate英文是『委託、代表』,表示可以代表一個function,可以將delegate想成物件導向的function pointer。

 1 24a924a57ba6b3f2b51fc9edb7ea4186.jpe 9310e85a14af99de4811ff4c77f1f911.jpe /**/ /* 
 21408c5260b2f05e450dee929db9be5f7.jpe(C) OOMusou 2007 http://oomusou.cnblogs.com
 31408c5260b2f05e450dee929db9be5f7.jpe
 41408c5260b2f05e450dee929db9be5f7.jpeFilename    : Delegate.cs
 51408c5260b2f05e450dee929db9be5f7.jpeCompiler    : Visual Studio 2005 / C# 2.0
 61408c5260b2f05e450dee929db9be5f7.jpeDescription : Demo how to use delegate
 71408c5260b2f05e450dee929db9be5f7.jpeRelease     : 05/01/2007 1.0
 8f466905a3bcb5dcef110eab799825254.jpe*/

 9 731655954c7be9d8835ece551b5385f8.jpe
10 731655954c7be9d8835ece551b5385f8.jpe using  System;
11 731655954c7be9d8835ece551b5385f8.jpe
12 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe class  main  222530190136c9c4cfd237cc0d5cff99.jpe {
131408c5260b2f05e450dee929db9be5f7.jpe  public delegate bool predicate(int i);
141408c5260b2f05e450dee929db9be5f7.jpe
15715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  public static bool isOdd(int i) 222530190136c9c4cfd237cc0d5cff99.jpe{
161408c5260b2f05e450dee929db9be5f7.jpe    return (i % 2> 0? true : false;
175bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

181408c5260b2f05e450dee929db9be5f7.jpe
19715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  public static bool isEven(int i) 222530190136c9c4cfd237cc0d5cff99.jpe{
201408c5260b2f05e450dee929db9be5f7.jpe    return ((i % 2> 0? false : true);
215bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

221408c5260b2f05e450dee929db9be5f7.jpe
23715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  public static bool greaterThan2(int i) 222530190136c9c4cfd237cc0d5cff99.jpe{
241408c5260b2f05e450dee929db9be5f7.jpe    return i > 2;
255bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

261408c5260b2f05e450dee929db9be5f7.jpe
27715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  public static void printArray(int[] arr, int size, predicate fn) 222530190136c9c4cfd237cc0d5cff99.jpe{
28715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    for(int i = 0; i != size; ++i) 222530190136c9c4cfd237cc0d5cff99.jpe{
291408c5260b2f05e450dee929db9be5f7.jpe      if (fn(arr[i])) 
301408c5260b2f05e450dee929db9be5f7.jpe        Console.WriteLine(arr[i].ToString());
315bcb1807ee3e00d2b3c225f0b3f5c751.jpe    }

325bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

331408c5260b2f05e450dee929db9be5f7.jpe
34715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  public static void Main() 222530190136c9c4cfd237cc0d5cff99.jpe{
35715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    int[] ia = 222530190136c9c4cfd237cc0d5cff99.jpe{123};
361408c5260b2f05e450dee929db9be5f7.jpe    
371408c5260b2f05e450dee929db9be5f7.jpe    Console.WriteLine("Odd222530190136c9c4cfd237cc0d5cff99.jpe");
381408c5260b2f05e450dee929db9be5f7.jpe    printArray(ia, 3new predicate(isOdd));
391408c5260b2f05e450dee929db9be5f7.jpe
401408c5260b2f05e450dee929db9be5f7.jpe    Console.WriteLine("Even222530190136c9c4cfd237cc0d5cff99.jpe");
411408c5260b2f05e450dee929db9be5f7.jpe    printArray(ia, 3new predicate(isEven));
421408c5260b2f05e450dee929db9be5f7.jpe
431408c5260b2f05e450dee929db9be5f7.jpe    Console.WriteLine("Greater than 2222530190136c9c4cfd237cc0d5cff99.jpe");
441408c5260b2f05e450dee929db9be5f7.jpe    printArray(ia, 3new predicate(greaterThan2));
455bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

46f466905a3bcb5dcef110eab799825254.jpe}


執行結果

731655954c7be9d8835ece551b5385f8.jpe Odd222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
1
731655954c7be9d8835ece551b5385f8.jpe
3
731655954c7be9d8835ece551b5385f8.jpeEven222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
2
731655954c7be9d8835ece551b5385f8.jpeGreater than 
2 222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
3


整個C#程式和C語言程式幾乎是一對一對應,定義function pointer型別變成了13行

731655954c7be9d8835ece551b5385f8.jpe public   delegate   bool  predicate( int  i);


表示predicate是一個delegate型別,代表一個迴傳為bool,參數為int的function。

而原來宣告function pointer型態的參數,則改成delegate型態

24a924a57ba6b3f2b51fc9edb7ea4186.jpe 9310e85a14af99de4811ff4c77f1f911.jpe    public   static   void  printArray( int [] arr,  int  size, predicate fn)  222530190136c9c4cfd237cc0d5cff99.jpe {


使用C++的Function Object
function object也稱為functor,用class或struct都可以,因為function object是利用constructor和對operator()做overloading,而這些都是public的,所以大部分人就直接使用struct,可少打public:這幾個字。

 1 24a924a57ba6b3f2b51fc9edb7ea4186.jpe 9310e85a14af99de4811ff4c77f1f911.jpe /**/ /* 
 21408c5260b2f05e450dee929db9be5f7.jpe(C) OOMusou 2007 http://oomusou.cnblogs.com
 31408c5260b2f05e450dee929db9be5f7.jpe
 41408c5260b2f05e450dee929db9be5f7.jpeFilename    : FuntionObject.cpp
 51408c5260b2f05e450dee929db9be5f7.jpeCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 61408c5260b2f05e450dee929db9be5f7.jpeDescription : Demo how to use function object
 71408c5260b2f05e450dee929db9be5f7.jpeRelease     : 05/01/2007 1.0
 8f466905a3bcb5dcef110eab799825254.jpe*/

 9 731655954c7be9d8835ece551b5385f8.jpe#include  < iostream >
10 731655954c7be9d8835ece551b5385f8.jpe
11 731655954c7be9d8835ece551b5385f8.jpe using   namespace  std;
12 731655954c7be9d8835ece551b5385f8.jpe
13 731655954c7be9d8835ece551b5385f8.jpetemplate  < typename T >
14 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe struct  isOdd  222530190136c9c4cfd237cc0d5cff99.jpe {
15715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
161408c5260b2f05e450dee929db9be5f7.jpe    return i%2? true : false;
175bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

18f466905a3bcb5dcef110eab799825254.jpe}
;
19 731655954c7be9d8835ece551b5385f8.jpe
20 731655954c7be9d8835ece551b5385f8.jpetemplate  < typename T >
21 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe struct  isEven  222530190136c9c4cfd237cc0d5cff99.jpe {
22715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
231408c5260b2f05e450dee929db9be5f7.jpe    return i%2? false : true;
245bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

25f466905a3bcb5dcef110eab799825254.jpe}
;
26 731655954c7be9d8835ece551b5385f8.jpe
27 731655954c7be9d8835ece551b5385f8.jpetemplate  < typename T >
28 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe struct  greaterThan2  222530190136c9c4cfd237cc0d5cff99.jpe {
29715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
301408c5260b2f05e450dee929db9be5f7.jpe    return i > 2;
315bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

32f466905a3bcb5dcef110eab799825254.jpe}
;
33 731655954c7be9d8835ece551b5385f8.jpe
34 731655954c7be9d8835ece551b5385f8.jpetemplate  < typename T >
35 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe struct  greaterThanAny  222530190136c9c4cfd237cc0d5cff99.jpe {
361408c5260b2f05e450dee929db9be5f7.jpe  T _val;
37715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  greaterThanAny(T n) : _val(n) 222530190136c9c4cfd237cc0d5cff99.jpe{}
38715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
391408c5260b2f05e450dee929db9be5f7.jpe    return i > _val;
405bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

41f466905a3bcb5dcef110eab799825254.jpe}
;
42 731655954c7be9d8835ece551b5385f8.jpe
43 731655954c7be9d8835ece551b5385f8.jpe
44 731655954c7be9d8835ece551b5385f8.jpetemplate  < typename T, typename U >
45 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe void  printArray(T beg, T end, U fn)  222530190136c9c4cfd237cc0d5cff99.jpe {
46715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  while(beg != end) 222530190136c9c4cfd237cc0d5cff99.jpe{
471408c5260b2f05e450dee929db9be5f7.jpe    if (fn(*beg))
481408c5260b2f05e450dee929db9be5f7.jpe      cout << *beg << endl;
491408c5260b2f05e450dee929db9be5f7.jpe      
501408c5260b2f05e450dee929db9be5f7.jpe    beg++;
515bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

52f466905a3bcb5dcef110eab799825254.jpe}
;
53 731655954c7be9d8835ece551b5385f8.jpe
54 24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe int  main()  222530190136c9c4cfd237cc0d5cff99.jpe {
55715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  int ia[] = 222530190136c9c4cfd237cc0d5cff99.jpe{123};
561408c5260b2f05e450dee929db9be5f7.jpe  
571408c5260b2f05e450dee929db9be5f7.jpe  cout << "Odd222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
581408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, isOdd<int>());
591408c5260b2f05e450dee929db9be5f7.jpe  
601408c5260b2f05e450dee929db9be5f7.jpe  cout << "Even222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
611408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, isEven<int>());
621408c5260b2f05e450dee929db9be5f7.jpe  
631408c5260b2f05e450dee929db9be5f7.jpe  cout << "Greater than 2222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
641408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, greaterThan2<int>());
651408c5260b2f05e450dee929db9be5f7.jpe  
661408c5260b2f05e450dee929db9be5f7.jpe  cout << "Greater than any222530190136c9c4cfd237cc0d5cff99.jpe" << endl;
671408c5260b2f05e450dee929db9be5f7.jpe  printArray(ia, ia + 3, greaterThanAny<int>(1));
68f466905a3bcb5dcef110eab799825254.jpe}


執行結果

731655954c7be9d8835ece551b5385f8.jpe Odd222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
1
731655954c7be9d8835ece551b5385f8.jpe
3
731655954c7be9d8835ece551b5385f8.jpeEven222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
2
731655954c7be9d8835ece551b5385f8.jpeGreater than 
2 222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
3
731655954c7be9d8835ece551b5385f8.jpeGreater than any222530190136c9c4cfd237cc0d5cff99.jpe
731655954c7be9d8835ece551b5385f8.jpe
2
731655954c7be9d8835ece551b5385f8.jpe
3


13行

731655954c7be9d8835ece551b5385f8.jpe template  < typename T >
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe
struct  isOdd  222530190136c9c4cfd237cc0d5cff99.jpe {
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  
bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe    
return i%2? true : false;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

f466905a3bcb5dcef110eab799825254.jpe}
;


使用了template,不過並非必要,只是顯示function object可以搭配template使用,而使用的技巧只是將function內的東西搬到operator()內。

34行

731655954c7be9d8835ece551b5385f8.jpe template  < typename T >
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe
struct  greaterThanAny  222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe  T _val;
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  greaterThanAny(T n) : _val(n) 
222530190136c9c4cfd237cc0d5cff99.jpe{}
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe  
bool operator() (T i) 222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe    
return i > _val;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe  }

f466905a3bcb5dcef110eab799825254.jpe}
;


是function object優於function pointer和delegate之處,由C語言和C#的範例可知,我們只能寫一個greaterThan2()的判斷式,若今天需求改變成greaterThan3,則又得再寫一個判斷式了,但因為function object是透過struct和class,別忘了struct和class還有個constructor,所以能藉由constructor對class做初始化,因此才能寫出greaterThanAny(),大於多少只要當成constructor帶入即可,而operator()的寫法一樣不變。

Conclusion
C語言、C#、C++皆提供了『將函數傳到另外一個函數』的機制,function pointer和delegate相當類似,而funtion object則功能更強。這裡澄清一個觀念,很多人認為function object就是為了要使用STL的algorithm才使用,這是標準的錯誤觀念,這是果而非因,因為STL的algorithm使用了function object的方式,所以我們才去配合,並不是只用在這個地方,事實上,我們自己的也可以使用function object,而且其比function pointer優越之處就在於function object多了constructor,所以比function pointer彈性更大。

實務上會用在哪些地方呢?大概有三個地方,callback,multi-thread和event,我會另外開一個專文專講function object的應用。

See Also
(原創) 如何使用Function Object? (C/C++) (STL)
(原創) 如何使用for_each() algorithm? (C/C++) (STL) 
(原創) 如何正確的使用迴圈(使用for_each)? (C/C++) (STL) (template)
(原創) 如何為程式碼加上行號? (C/C++) (STL)
(原創) Function Pointer、Delegate與Function Object (C/C++) (template) (.NET) (C#)

Reference
子由,深度學習C++ 2/e,博碩文化,2006
夢在天涯的函数指针实例


转载请注明本文地址: (原創) Function Pointer、Delegate和Function Object (C/C++) (template) (.NET) (C#)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值