這篇文章把函數指標的各種常用情況做了一個詳解的總結。
1. 指向普通函數的指標
很簡單,如下的例子可以說明基本格式和用法:
int int_add(int a, int b)<br />{<br /> return (a+b);<br />}<br />int int_sub(int a, int b)<br />{<br /> return (a-b);<br />}<br />int (*int_operator)(int, int) = int_add;</p><p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> cout<<int_operator(4, 5)<<endl; // output 9<br /> int_operator = int_sub;<br /> cout<<int_operator(4, 5)<<endl; // output -1<br /> return 0;<br />}<br />
上例中,int_operator會被編譯器解釋成類型int(*)(int, int)的一個指標。
調用方式還可以寫作:(*int_operator)(4,
5),這樣的好處是讓人一眼就能看到int_operator是一個函數指標。
注意:函數指標和指向函數的傳回值的類型和參數都必須嚴格一致;
2. 函數指標數組
我們還可以聲明一個函數指標的數組,比如:
int (*pFuncArray[10])();
[]的優先順序高於*,該語句將pFuncArray聲明為擁有10個元素的數組,每一個元素都是指向一個函數的函數指標,該函數沒有參數,傳回值類型為int;
注意不能寫作:int
((*pFuncArray)[10])(),這樣會產生編譯錯誤;
(*pFuncArray)[10]表明了pFuncArray是一個指標,該指標指向一個’含有 10個元素的數組’;
其類型為int()(),顯然,編譯不能通過。
將上面的聲明轉換為typedef格式,會使程式可讀性增加:
typedef int(*pFunc)();
pFunc pFuncArray[10];
如果需要調用其中的第三個函數,那麼調用方式為:pFuncArray[2]();
3. 指向‘函數指標數組’的指標
還可以聲明一個指向‘函數指標數組’的指標,比如下面的例子代碼:
int cmp_len(const char *str1, const char *str2)<br />{return ((int)strlen(str1) - (int)strlen(str2));}<br />int cmp_str(const char *str1, const char *str2)<br />{return strcmp(str1, str2);}</p><p>typedef int(*PCMP_FUNC)(const char*, const char*);</p><p>PCMP_FUNC pCmpFuncs[2] =<br />{<br /> cmp_len,<br /> cmp_str,<br />};<br />// 聲明指向pCmpFuncs的指標<br />PCMP_FUNC (*ppCmps)[2] = &pCmpFuncs;
聲明分解說明如下:
(*ppCmps):表明ppCmps是一個指標;
(*ppCmps)[2]:後面緊跟[2],表明ppCmps是一個指向‘兩個元素數組’的指標
PCMP_FUNC表明了該數組元素的類型,它是指向函數的指標,傳回值為int,有兩個const
char*類型的參數;
實際上語句PCMP_FUNC (*ppCmps)[2] = &pCmpFuncs;
將會被編譯器解釋為:
int
(*(*ppCmps)[2])(const
char*, const char*) = &pCmpFuncs;
聲明分解:
(*ppCmps):表明ppCmps是一個指標;
(*ppCmps)[2]:後面緊跟[2],表明ppCmps是一個指向‘兩個元素數組’的指標
int (*)(const char*, const char *):表明了該數組元素的類型,它是指向函數的指標,傳回值為int,有兩個const char*類型的參數;
3. 函數指標與類
在C++語言中,使用函數指標可以指向類的一個成員函數或變數,雖然這種用法很少能用到,至少我是沒有用過,不過瞭解一下還是有點必要的。
為了支援這類指標,C++有三個特殊的運演算法符:::*,.->,.*;
指向成員函數的指標必須與向其賦值的函數類型匹配,這包括:1)參數的類型和個數;2)傳回值類型;3)它所屬的類型;
指向成員變數的指標必須與向其賦值的變數類型匹配,這包括:1)變數類型;2)它所屬的類型;
成員函數和變數必須被綁定到一個對象或者指標上,然後才能得到調用對象的this指標,然後才能指向成員變數或函數;
類AClass的成員變數int m_iValue,其完整類型是:int型的類AClass的成員m_iValue;
類AClass的成員函數int Add(int),其完整類型是:傳回值為int型,帶一個int型別參數的類AClass的成員Add;
注意:指向類的靜態變數或靜態成員函數的指標和普通成員不同;
3.1 指向類成員變數的指標
有了上面的一些說明,看下面的例子就很容易理解了;
.* 是一個新的操作符,表明是指向成員操作符的指標(另一個是->*,是指標對象的調用方式)
<br />class AClass<br />{<br />public:<br /> void Add(int a){m_iValue += a;}<br /> int m_iValue;<br />};<br />int _tmain(int argc, _TCHAR* argv[])<br />{<br /> AClass a;<br /> // 聲明並指向AClass的一個成員變數的指標<br /> int AClass::*pValue = &AClass::m_iValue;<br /> // 或者如下方式:<br /> // int AClass::*pValue;// 指標變數聲明<br /> // pValue = &AClass::m_iValue;// 指向A的m_iValue成員<br /> a.*pValue = 4; // 使用方式,賦值<br /> cout<<a.m_iValue<<endl; // 輸出4<br /> return 0;<br />}
3.2 指向類成員函數的指標
有了上面的一些說明,看下面的例子就很容易理解了;
下面的例子中,注意調用方式:(a.*pAAdd)(5);不能寫作a.*pAAdd(5);
因為操作符()的優先順序是高於.*的因此,它將被解釋為a.*(pAAdd(5));顯然這是不被支援的。
<br />class AClass<br />{<br />public:<br /> void Add(int a){m_iValue += a;}<br /> int m_iValue;<br />};<br />// 指向類AClass成員函數的指標的聲明方式<br />typedef void (AClass::*pAFunc)(int);<br />// 聲明一個指向AClass::Add()的函數指標<br />pAFunc pAAdd = &(AClass::Add);</p><p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> AClass a;<br /> // 聲明並指向AClass的一個成員變數的指標<br /> int AClass::*pValue = &AClass::m_iValue;<br /> // 或者如下方式:<br /> // int AClass::*pValue;// 指標變數聲明<br /> // pValue = &AClass::m_iValue;// 指向A的m_iValue成員<br /> a.*pValue = 4; // 使用方式,賦值<br /> cout<<a.m_iValue<<endl; // 輸出<br /> (a.*pAAdd)(5); // 指向成員函數指標的調用方式<br /> cout<<a.m_iValue<<endl; // 輸出<br /> return 0;<br />}
3.3 指向類靜態成員的指標
類的靜態成員屬於該類的全域對象和函數,並不需要this指標;因此指向類靜態成員的指標聲明方式和普通指標相同。
該類指標和普通指標的聲明和調用方式完全相同;唯一的不同就是設定指向的對象時,仍然需要類資訊,這一點和指向普通成員的指標相同。
下面的例子可以說明使用方式。
class AClass<br />{<br />public:<br /> static void Add(int a){m_iValue += a;}<br /> static int m_iValue;<br />};<br />int AClass::m_iValue;</p><p>typedef void(*pAAdd)(int);</p><p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> // 聲明並指向AClass的一個靜態成員變數的指標<br /> int *pValue = &AClass::m_iValue;<br /> // 或者如下方式:<br /> // int *pValue;// 指標變數聲明<br /> // pValue = &AClass::m_iValue;// 指向A的m_iValue成員<br /> *pValue = 4; // 使用方式同普通指標,賦值<br /> cout<<*pValue<<endl; // 輸出<br /> pAAdd p = &AClass::Add;<br /> p(5); // 調用方式同普通函數指標<br /> cout<<*pValue<<endl; // 輸出<br /> return 0;<br />}