惱人的函數指標(二),惱人函數指標
原文連結:http://www.cnblogs.com/AnnieKim/archive/2011/12/04/2275589.html
前面曾寫過一篇惱人的函數指標(一),總結了普通函數指標的聲明、定義以及調用,還有函數指標數組,函數指標用作返回值等。但是作為C++的研讀,我發現我漏掉了一個最重要的內容,就是指向類成員的指標,這裡將做相應補充(相關代碼測試環境為vs 2010)。
指向類成員的指標總的來講可以分為兩大類四小類(指向資料成員還是成員函數,指向普通成員還是靜態成員),下面一一做介紹:
一、指向類的普通成員的指標(非靜態)
1、指向類成員函數的指標
簡單的講,指向類成員函數的指標與普通函數指標的區別在於,前者不僅要匹配函數的參數類型和個數以及返
回值類型,還要匹配該函數指標所屬的類類型。總結一下,比較以下幾點:
a)參數類型和個數
b)返回值類型
c)所屬的類類型(特別之處)
究其原因,是因為非靜態成員函數必須被綁定到一個類的對象或者指標上,才能得到被調用對象的this指標,
然後才能調用指標所指的成員函數(我們知道,所有類的對象都有自己資料成員的拷貝,但是成員函數都是共
用的,為了區分是誰調用了成員函數,就必須有this指標,this指標是隱式的添加到函數參數列表裡去的)。
明白了這點,接下來就簡單了。
聲明:與普通函數作為區分,指向類的成員函數的指標只需要在指標前加上類類型即可,格式為:
typedef 返回值 (類名::*指標類型名)(參數列表);
賦值:只需要用類的成員函數地址賦值即可,格式為:
指標類型名 指標名 = &類名::成員函數名;
注意:這裡的這個&符號是比較重要的:不加&,編譯器會認為是在這裡調用成員函數,所以需要給出參數列
表,否則會報錯;加了&,才認為是要擷取函數指標。這是C++專門做了區別對待。
調用:調用方法也很簡單,針對調用的對象是對象還是指標,分別用.*和->*進行調用,格式為:
(類對象.*指標名)(參數列表);
(類指標->*指標名)(參數列表);
(既然是指標, 不管是資料類型的指標, 還是函數指標, 不管是普通函數指標還是類函數成員指標, 都應該按照
習慣加一個&去取地址符, 不過對於普通函數, 編譯器做了特殊的處理, 不過我本人認為會讓人誤解, 所有東
西, 涉及到類的, 基本上都會有個類域; 當應引用指標的值的時候, 我們應該和普通的指標一樣, 用*去引用
符。提醒一下大家, 因為類的.和->運算子的優先順序都高於去引用符*, 所以上面的能那麼些, 不清楚的讀者可
以做自己看看運算子的優先順序.)
注意:這裡的前面一對括弧是很重要的,因為()的優先順序高於成員操作符指標的優先順序。
下面舉個簡單的例子就一目瞭然了:
class A;typedef void (A::*NONSTATICFUNCPTR)(int); //typedef class A{public: void NonStaticFunc(int arg) { nonStaticMember = arg; cout << nonStaticMember << endl; }private: int nonStaticMember;}; int main(){ NONSTATICFUNCPTR funcPtr = &A::NonStaticFunc; A a; (a.*funcPtr)(10); //通過對象調用 A *aPtr = new A; (aPtr->*funcPtr)(10); //通過指標調用 return 0;}
2、指向類資料成員的指標
成員函數搞懂了,資料成員也就easy了,只要判斷以下兩點是否一致即可:
a)資料成員類型
b)所屬的類類型
另外,聲明、賦值還有調用方法等這些是和前面類似的,再舉個例子吧:
class A;typedef int(A::*NONSTATICDATAPTR); //typedef class A{public: A(int arg) :nonStaticMember(arg){} int nonStaticMember;}; int main(){ NONSTATICDATAPTR dataPtr = &A::nonStaticMember; A a(10); cout << a.*dataPtr; //通過對象引用 A *aPtr = new A(100); cout << aPtr->*dataPtr; //通過指標引用 return 0;}
運行結果,當然是各自輸出10和100啦。
二、指向類的靜態成員的指標
類的靜態成員和普通成員的區別在於,他們是不依賴於具體對象的,所有執行個體化的對象都共用同一個靜態成員,
所以靜態成員也沒有this指標的概念。所以,指向類的靜態成員的指標就是普通的指標。
看下面的例子就明白了:
typedef const int *STATICDATAPTR;typedef int(*STATICFUNCPTR)(); //跟普通函數指標是一樣的 class A{public: static int StaticFunc() { return staticMember; }; static const int staticMember = 10;}; int main(){ STATICDATAPTR dataPtr = &A::staticMember; STATICFUNCPTR funcPtr = &A::StaticFunc; cout << *dataPtr; //直接解引用 cout << (*funcPtr)(); return 0;}
最後註明一下,顯然的,要使用(&類名::成員名)擷取指向成員的指標,首先這個成員必須是對外可見的哦,即public的,不然是沒有許可權擷取的^^。
寫到此,簡單總結一下就是:
1)靜態和普通的函數指標沒啥區別;
2)非靜態加一個類局限一下即可。
不知道以後還會不會有函數指標相關的內容,先到此完結吧。
有錯誤歡迎指正,我會及時修改^^。
(完)
函數指標與指標的不同在什地方?
指標是C語言的一種資料類型;
函數指標是C指標的一種。
問“函數指標與指標的區別在哪裡?” 說明LZ對指標還不慎瞭解。修改一下你的問題:
“函數指標與整型指標的區別在哪裡?”
這樣的話,我就告訴你:
1. 二者都是指標
2. 函數指標裡存放的是一個函數的首地址,而整型指標裡放的是一個整型變數的地址;
3.指標本身是參考型別。所以使用時都要解除引用。函數指標與整型指標解除引用的方式不同。整型指標有兩種方式解除引用:
如對整型指標pi:
int i = 0;
int *pi = &i;
解除引用方法一: *pi
解除引用方法二: pi[0]
對函數指標pf:
int f(int);
int (*pf)(int) = f ;
解除引用方法: pf(8);
整型指標解除引用方法二: pi[0]更像數組。也更像函數指標解除引用的方法,原因是:
數組名、和函數名 的本質都是地址。指標的本質也是地址。
4。從以上例子中看到賦值形式不同
函數指標 pf = f; (不用 &。其實用也一樣)
整型指標 pi = &i;
原因是數組名、和函數名 的本質都是地址,而整型變數的本質(當作為左值【如果允許】或右值時)是地址裡的值。
5. 對函數指標,一般不可以做遞增操作 如:pf++ 99.9999%會崩潰
如果要訪問函數陣列,需要使用函數指標數組
怎用函數指標做參數?
首先,聲明函數指標的類型是這樣聲明的:
void (*pFun)(int,int)
void 這個函數傳回值的類型,pFun 這個指標的名稱,(int x,int y) 這個函數的參數列表。
第二,函數名就是函數指標,如有如下函數
void hello()
{
printf("hello world!\n");
}
那hello就是這個函數的指標。
第三,實際例子:
#include<cstdio>
void hello(){
printf("hello world!\n");
}
void runFun(void (*pFun)()){
pFun();
}
void main()
{
runFun(hello);
}
首先,定義hello函數。
第二,定義runFun函數,這個函數的參數是一個 函數指標,上面已經說過定義方法,runFun直接使用傳過來的 函數指標 執行函數。
第三,在main中將hello函數的指標(即hello)傳進runFun。