现在的位置: 首页 > 综合 > 正文

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

2013年07月08日 ⁄ 综合 ⁄ 共 4095字 ⁄ 字号 评论关闭

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#include <iostream>
 2
 3using namespace std;
 4
 5void printArrayOdd(int* beg, int* end) {
 6  while(beg != end) {
 7    if ((*beg)%2)
 8      cout << *beg << endl;
 9      
10    beg++;
11  }

12}

13
14void printArrayEven(int* beg, int* end) {
15  while(beg != end) {
16    if (!((*beg)%2))
17      cout << *beg << endl;
18      
19    beg++;
20  }

21}

22
23void printArrayGreaterThan2(int* beg, int* end) {
24  while(beg != end) {
25    if ((*beg)>2)
26      cout << *beg << endl;
27      
28    beg++;
29  }

30}

31
32int main() {
33  int ia[] = {123};
34  
35  cout << "Odd" << endl;
36  printArrayOdd(ia, ia + 3);
37
38  
39  cout << "Even" << endl;
40  printArrayEven(ia, ia + 3);
41  
42  cout << "Greater than 2" << endl;
43  printArrayGreaterThan2(ia, ia + 3);
44}

執行結果

Odd
1
3
Even
2
Greater than 
2
3

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

使用C語言的Function Pointer

 1/* 
 2(C) OOMusou 2007 http://oomusou.cnblogs.com
 3
 4Filename    : FuntionPointer.cpp
 5Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 6Description : Demo how to use function pointer
 7Release     : 05/01/2007 1.0
 8*/

 9#include <iostream>
10
11using namespace std;
12
13typedef bool (*predicate)(int);
14
15bool isOdd(int i) {
16  return i%2? true : false;
17}

18
19bool isEven(int i) {
20  return i%2? false : true;
21}

22
23bool greaterThan2(int i) {
24  return i > 2;
25}

26
27void printArray(int* beg, int* end, predicate fn) {
28  while(beg != end) {
29    if ((*fn)(*beg))
30      cout << *beg << endl;
31      
32    beg++;
33  }

34}

35
36int main() {
37  int ia[] = {123};
38  
39  cout << "Odd" << endl;
40  printArray(ia, ia + 3, isOdd);
41  
42  cout << "Even" << endl;
43  printArray(ia, ia + 3, isEven);
44  
45  cout << "Greater than 2" << endl;
46  printArray(ia, ia + 3, greaterThan2);
47}

執行結果

Odd
1
3
Even
2
Greater than 
2
3

第13行

typedef bool (*predicate)(int);

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

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

void printArray(int* beg, int* end, predicate fn) {

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

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

 1/* 
 2(C) OOMusou 2007 http://oomusou.cnblogs.com
 3
 4Filename    : Delegate.cs
 5Compiler    : Visual Studio 2005 / C# 2.0
 6Description : Demo how to use delegate
 7Release     : 05/01/2007 1.0
 8*/

 9
10using System;
11
12class main {
13  public delegate bool predicate(int i);
14
15  public static bool isOdd(int i) {
16    return (i % 2> 0? true : false;
17  }

18
19  public static bool isEven(int i) {
20    return ((i % 2> 0? false : true);
21  }

22
23  public static bool greaterThan2(int i) {
24    return i > 2;
25  }

26
27  public static void printArray(int[] arr, int size, predicate fn) {
28    for(int i = 0; i != size; ++i) {
29      if (fn(arr[i])) 
30        Console.WriteLine(arr[i].ToString());
31    }

32  }

33
34  public static void Main() {
35    int[] ia = {123};
36    
37    Console.WriteLine("Odd");
38    printArray(ia, 3new predicate(isOdd));
39
40    Console.WriteLine("Even");
41    printArray(ia, 3new predicate(isEven));
42
43    Console.WriteLine("Greater than 2");
44    printArray(ia, 3new predicate(greaterThan2));
45  }

46}

執行結果

Odd
1
3
Even
2
Greater than 
2
3

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

抱歉!评论已关闭.