其實指針並不可怕,可怕的是你那一顆不自信的心和對於指針的畏懼! 說明,寫在前面: .本文的內容嚴格按照C++標準而寫,可能與C語言的標準有出入,C語言用戶請只作參考。 .我書寫了大量的代碼用於驗證本文內容的正確性,我所用的編譯器是微軟的Visual Studio 2010 SP1(中文旗艦版)和GNU的MinGW 20111108。 .若是讀者也要寫代碼來驗證本文內容的正確性,請使用和我同樣的編譯器或者使用一些版本較新的編譯器。由於一些舊版本的編譯器對C++標準的支持是不完整的,好比Visual C++ 6.0。用Visual C++ 6.0可能會對正確的標準C++代碼報錯,固然,對本文的內容僅是可能,而且可能性應該不大。個人Visual C++ 6.0裝在虛擬機上,時間關係,沒有在那上面測試本文的內容。 .個人測試代碼暫時不提供給讀者。 .若是沒有學過C++,或者是C++初學者,或者對C++的掌握不是很精純,那麼,請不要先閱讀本文,由於我怕打擊你的信心。請達到必定水準後再來閱讀本文。由於本文是C++的進階文章。 正文: 在通向C++的道路上,函數與指針是不可缺乏的元素,那麼,當二者邂逅時,又會發生什麼呢,下面就讓我帶你走進它們的世界。 咱們將用五個部分來講明幾個重要的概念:返回指針的函數,指向函數的指針(函數指針),返回指向函數的指針的函數。 注意:C++容許函數在聲明時不寫形參的名字,而只寫形參的類型,如: int abc(int i);在聲明能夠寫爲int abc(int); 所以本文的聲明都省略形參名。但注意,在實現時是不能省略的。 .返回指針的函數和指向函數的指針(函數指針) 返回指針的函數聲明示例以下: bool *pf(const string&, const string&); 這裏,pf是一個函數,返回的是一個bool類型的指針。 指向函數的指針聲明示例以下: bool (*pf)(const string&, const string&); 這裏,pf是一個指針,指向的是一個函數。這個函數的返回類型是bool,並有兩個const string型的引用形參。咱們把pf叫作一個函數指針。 .用typedef簡化函數指針的定義及其初始化,賦值和使用。 函數指針類型至關冗長,使用typedef爲指針類型定義同義詞,可將函數指針的使用大大簡化: typedef bool (*cmpFcn)(const string&, const string&); 這裏,cmpFcn是一個函數指針類型,不是一個具體的指針。就像類和對象的關係同樣。 如今能夠用cmpFcn來定義指向返回類型是bool,並有兩個const string型的引用形參的函數的指針了。 假設有一個函數: bool lengthCompare(const string&, const string&); 在標準C++中,除了用做函數的左操做數外,對函數名lengthCompare的任何使用都被解釋爲以下類型的指針 bool(*)(const string&, const string&); 顯然這是一個函數指針。 所以,咱們能夠這樣: cmpFcn pf1=0;//正確。用0值爲函數指針初始化。 cmpFcn pf2=lengthCompare;//正確。用同類型的函數名爲函數指針初始化。 pf1=lengthCompare;//正確。用同類型的函數名爲函數指針賦值。 pf2=pf1;//正確。用同類弄的函數指針爲函數指針賦值。 我在上面的註釋中反覆強調同類型這個詞,由於函數指針的初始化和賦值只能是0值表達式或者同類型的函數或者同類型的函數指針。例如假設有函數: string::size_type sumLength(const string&, const string&); bool cstringCompare(char*, char*); 對如下操做就有: cmpFcn pf; pf=sumLength;//錯誤。不是同類型。 pf=cstringCompare;//錯誤。不是同類型。 pf=lengthCompare;//正確.同類型。 注:引用函數名至關於對函數名應用取地址操做符,所以如下兩句代碼是等效的: cmpFcn pf1=lengthCompare; cmpFcn pf1=&lengthCompare; 使用函數指針的方法: 若 cmpFcn pf=lengthCompare; 則如下三句代碼等效: lengthCompare("hi","bye"); pf("hi","bye"); (*pf)("hi","bye"); .函數指針用做函數的形參 函數指針是能夠用做函數的形參的,而且這種形參有如下兩種等效的寫法: void useBigger(const string&, const string&, bool(const string&, const string&)); void useBigger(const string&, const string&, bool(*)(const string&, const string&)); 這裏說明,標準C++容許將函數的形參定義爲一個函數類型,可是這個函數類型必須是指向函數的指針,而不能是函數,所以上面中,編譯器在編譯時會將 bool(const string&, const string&));自動轉換爲 bool(*)(const string&, const string&)); 也就是說函數類型的形參所對應的實參將被自動轉換爲指向相應函數類型的指針。 可是有一點要注意,當返回的是函數時,一樣的轉換操做沒法自動實現,而必須顯示指明。 如: typedef int func(int*, int); //注意,上面定義的不是函數指針類型,並且普通函數類型 對以下操做有: void f1(func);//正確。函數類型func將自動轉換爲相應的函數指針類型 func f2(int);//錯誤。返回值是函數,自動轉換失效。 func *f3(int);//正確。返回值是函數指針不是函數。 第二句第三句的區別就是,返回函數類型時是要轉換爲相應函數指針的,可是不是由編譯器自動完成的,必須由程序員顯示指明。 .返回指向函數的指針的函數 聽起來太拗口了,可是在標準C++中,這是能夠的,可是,正確地寫出這種返回類型也是至關不容易的,我舉個例子: int (*ff(int))(int*, int); 我來解釋這個定義: ff(int) 這是將ff聲明爲一個函數,並帶有一個int類型的形參。這個函數返回的是這樣一個指針: int (*)(int*, int); 若是你前面的內容看懂了,就容易發現這就是前面說的一個函數指針。 如今二者一結合,就是返回指向函數的指針的函數,其本質是函數,而不是指針。 咱們一樣能夠用typedef來達到簡化的目的。 typedef int (*PF)(int*, int); PF ff(int); .指向重載函數的指針 標準C++容許函數指針指向重載的函數,但函數指針的類型必須和重載函數的某一個版本精確匹配。舉例說明: 如今有兩個重載函數,聲明以下: extern void ff(vector<double>); extern void ff(unsigned int); 那麼函數指針 void (*pf1)(unsigned int)=&ff;//&ff能夠寫成ff,等效,前面講過 將正確匹配函數void ff(unsigned int); void (*pf2)(int)=&ff;//錯誤。沒有能夠匹配的函數。 由於沒有void ff(int);這樣的函數 double (*pf3)(vector<double>)=&ff//錯誤。沒有能夠匹配的函數。 由於沒有double ff(vector<double>);這樣的函數。 本文完。 年04月28日 中國寧波