//=====================================================================
//TITLE:
// C++ VS C#(7):指向函數的指針和委托
//AUTHOR:
// norains
//DATE:
// Thursday 17-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//Modify
// AM,Thursday 17-January-2011 初稿
// PM,Thursday 17-January-2011 修改C++調用的方式
//=====================================================================
1. 指向函數的指針和委托
開篇點題,假設我有兩個形參和返回類型都一樣的兩個函數,如:
view plaincopy to clipboardprint?
static int Multiply(int Param1,int Param2)
{
return Param1 * Param2;
}
static int Divide(int Param1,int Param2)
{
return Param1 / Param2;
}
static int Multiply(int Param1,int Param2)
{
return Param1 * Param2;
}
static int Divide(int Param1,int Param2)
{
return Param1 / Param2;
}
現在我不想直接調用這兩個函數,而是間接通過某種方式來進行調用。這話看起來似乎有點拗口,不直接,我們還是來換一種說法。假設我們有一個容器,而該容器能夠獲取函數的相關信息,但我們不必去關心調用函數是什麼,只需要調用容器,讓容器去選擇相應的函數即可。
這個所謂的容器,無論是在C++還是在C#,都是存在的。那麼,我們首先從C++開始。
在C++中,這個容器的名字叫做:指向函數的指針。沒錯,就是指針。指針絕對是C++的精髓,就像萬金油一樣,放到哪裡都是真理。只不過這裡的指針是指向函數的,所以聲明起來似乎有點怪異,代碼如下:
view plaincopy to clipboardprint?
//定義兩個變量,在函數調用時使用
int a = 10;
int b = 20;
//聲明一個指向函數的指針
int (*pFunc)(int,int);
//將函數地址賦值給指針
if(bDiv != FALSE)
{
pFunc = Divide;
}
else
{
pFunc = Multiply;
}
//調用指向的函數
pFunc(a,b);
//調用也可使用這種形式
(*pFunc)(a,b);
//定義兩個變量,在函數調用時使用
int a = 10;
int b = 20;
//聲明一個指向函數的指針
int (*pFunc)(int,int);
//將函數地址賦值給指針
if(bDiv != FALSE)
{
pFunc = Divide;
}
else
{
pFunc = Multiply;
}
//調用指向的函數
pFunc(a,b);
//調用也可使用這種形式
(*pFunc)(a,b);
賦值好理解,和普通的賦值沒什麼區別;調用理解上也不算很難,簡單點來看也就是相當於Multiply(a,b),復雜一點的加*也可當成是獲取指針指向的函數來理解。而聲明的這個語句:int (*pFunc)(int,int),怎麼咋看咋別扭呢?沒辦法,這個我們也改變不了,因為標准是定死的。只不過,C++有趣就有趣在這裡,你可以使用typedef來使得聲明更清晰!不信,我們一起來看:
view plaincopy to clipboardprint?
//定義一個函數指針類型,並且該類型名為Func
typedef int (*Func)(int,int);
//聲明一個指向函數的指針
Func pFunc;
//定義一個函數指針類型,並且該類型名為Func
typedef int (*Func)(int,int);
//聲明一個指向函數的指針
Func pFunc;
相對之前的直接聲明,這樣的聲明是不是更加清楚?當然,代價就是多出一行typedef代碼。
至此,C++的描述就暫時告一段落,我們接下來看看C#。在C#中,是不存在指針的,自然也不會有指向函數的指針這種玩意,取而代之的是委托。委托的聲明非常類似於函數,但它不帶函數體,並且需要使用delegate關鍵字。如果以C#來實現,那麼代碼如下:
view plaincopy to clipboardprint?
//定義一個委托FuncDelegate,其返回類型和形參與Multiply和Divide相同
delegate int FuncDelegate(int Param1, int Param2);
//聲明兩個變量,用來函數定義用
int a = 10;
int b = 20;
//聲明一個委托變量
FuncDelegate Func;
//給委托變量賦值
if (bDiv != false)
{
Func = new FuncDelegate(Divide);
}
else
{
Func = new FuncDelegate(Multiply);
}
//調用對應的函數
Func(a,b);
//定義一個委托FuncDelegate,其返回類型和形參與Multiply和Divide相同
delegate int FuncDelegate(int Param1, int Param2);
//聲明兩個變量,用來函數定義用
int a = 10;
int b = 20;
//聲明一個委托變量
FuncDelegate Func;
//給委托變量賦值
if (bDiv != false)
{
Func = new FuncDelegate(Divide);
}
else
{
Func = new FuncDelegate(Multiply);
}
//調用對應的函數
Func(a,b);
C#中采用委托的方式,其實和C++的typedef非常相像,都是必須先定義一個類型,然後用該類型去聲明一個變量。最大的不同在賦值階段,C++只需要簡單的將函數地址賦給指針,而C#必須用new聲明一個對象,並且還要求相應的函數作為形參傳入。在這個階段,似乎C#顯得更為復雜。到了調用階段,C++和C#都可以容器後加個括號就能完成調用,但C++還多了一種*的方式。雖然這種方式有點雞肋,但畢竟多了一種樂趣,何樂而不為呢?