在c++裡說到函式指標,有很多人都是避而遠之,更別說什麼「遞迴函式指標」了。但是實際上有的東西越是神秘,其原理反而越簡單,所以我這裡就先賣乙個關子,假裝介紹乙個「高深的技巧」一樣做這個開場白了。
什麼是「函式指標」呢?(別砸我!我想從頭開始講)比如我們定義了乙個函式:
int f(char);
我們先不管它的實現,我們只知道它的申明,那麼我們就可以定義乙個函式指標fp來指向它:
funcptr fp = f; //或:fp = &f;老實說,這2種寫法有什麼不同,我也不知道
fp(); //執行f函式
注意c++是強型別安全的,也就是說,如果fp不是和f同型別的話,是不能賦值的,即使它們占用的儲存空間一樣大,甚至都是32位的整數(在別的系統裡可能不同)。比如:
void g(char);
fp = g; //error:type mi**atch!
那麼fp是什麼型別的呢?
typedef int (* funcptr)(char);
fp的型別是funcptr。我這裡只是簡單的介紹,為後面的討論做鋪墊。如果你對這些**有什麼不懂的,我建議你還是看看專門的c++入門書籍。
現在我開始介紹「遞迴函式指標」。想象一下,如果乙個函式能返回自己的指標,那麼這個函式應該怎樣定義呢?
funcptr fp = f(/*whatever*/); //執行f函式,得到函式指標
fp = fp(/*whatever*/); //執行f函式,得到函式指標
fp = fp(/*whatever*/); //執行f函式,得到函式指標
//...and so on
我們現在是在c++裡,不是在c或是彙編裡,在那些語言裡沒有型別檢查,只要是儲存空間一樣大,什麼都可以相互等同。在c++裡,我們享受了型別安全的優點,現在該修補它帶來的一些「缺陷」來當作回報了。也許有人很快會在腦海裡閃過一些**,類似於:
typedef funcptr (* funcptr)(/*whatever*/); //對應的函式指標的定義
funcptr f(/*whatever*/) //乙個函式的定義
這段**顯然是有問題的,原因不用我說,那麼該怎麼解決這個問題呢?我們把目光集中到了臨時變數上。對於return by value(沒找到合適的漢語對應)的c++函式,其返回值都是靠臨時變數來傳送的。比如乙個函式function:
typea function() //return type is typea
編譯器會產生這樣的等同**:
void function(typea _tmp_)
注意到函式的返回型別(_tmp_的型別)和a的型別是一樣的,都是typea。那麼能不能使_tmp_和a的型別不同呢?當然可以了!只要a能轉化成_tmp_,或說_tmp_能從a構建出來,比如:
class typea{};
class typeb
typeb(const typea &){} //construct b from a
}; 從乙個typea型別的物件可以構建乙個typeb型別的物件,那麼我們可以這樣修改上面的函式:
typeb function()
我們討論到這裡,也許有人會想到我下一步要做什麼了!對了,由於在函式申明中,函式返回的值型別不能是函式本身的指標型別——不能簡單的遞規typedef,這在前面的例子裡大家都看到了——那麼我們需要乙個型別轉化:從函式本身的指標型別轉化成另乙個型別,再在賦值的時候轉化回來,就可以了。於是我們定義的了乙個類:
class _funcptrclass
; _funcptr f(/*whatever*/) //函式f定義
typedef _funcptrclass (* funcptr)(/*whatever*/); //函式指標型別funcptr定義
我們來看看_funcptrclass類應該具有哪些特點。首先,它要能從funcptr物件構建出來,並且要負責傳遞這個指標的值,所以它需要乙個funcptr型別的成員變數,和乙個定製的建構函式。注意,funcptr的定義是在_funcptrclass之後的,所以實際上在_funcptrclass內應該重新定義funcptr:
class _funcptrclass
//定製的建構函式
private:
funcptrinclass f_; //funcptrinclass型別的成員變數
}; 現在函式f的定義就是完全合法的了,並且可以成功的執行。不過,好像還缺點兒什麼——怎麼樣得到臨時變數_funcptrclass-object裡的函式指標的值呢?是的,我們還缺乙個轉換的函式,這可以通過乙個簡單的operator做到:
class _funcptrclass
operator funcptrinclass() //從_funcptrclass到funcptrinclass轉換的函式
private:
funcptrinclass f_;
}; 這就是我們最終版本的_funcptrclass,配合上:
_funcptr f(/*whatever*/)
typedef _funcptrclass (* funcptr)(/*whatever*/);
我們就能放心的執行以前的**了:
funcptr fp = f(/*whatever*/); //執行f函式,得到函式指標
fp = fp(/*whatever*/); //執行f函式,得到函式指標
fp = fp(/*whatever*/); //執行f函式,得到函式指標
//...and so on
好了,大功告成!
也許有人會認為我這裡講的例子一點實際用處也沒有,的確,我也這樣認為。不過我並不認為這個技巧是沒用的。任何人說某個東西一點用處也沒有,都有點武斷的嫌疑。我所闡述的並不是這樣的乙個例子,而是這樣的一種技巧,我也是從別的書上看過來的,但是我並不認為那位作者是在講乙個毫無用處的例子。
怎樣定義函式指標陣列
如果乙個指標指向某個函式,那麼它便是函式指標。有時候我們如果需要在乙個迴圈中,每次呼叫不同的函式 這些函式的返回值和引數相同,函式名不同,實現不同 那麼就可以使用函式指標陣列來使 更加簡練和易讀。那麼,怎樣定義函式指標陣列呢?在定義函式指標陣列之前,需要首先知道什麼是函式指標。函式指標的定義形象點來...
C 裡的函式指標
今天在寫乙個小功能的時候,寫了三個介面函式,結果 基本類似,只是其中呼叫的函式不一樣,而且這幾個呼叫函式的宣告是完全一樣的。根據 的抽象三原則裡的rules of three,應該得抽象一下了。最直接的想法就是抽出乙個共用函式,三個介面函式呼叫這個共用函式,通過傳入不同的函式指標,來實現不同的功能。...
定義裡的this指標
在類的定義過程中,經常會使用到this關鍵字,那麼我們來理解一下this指標在類定義中的作用。this只能在成員函式中使用 全域性函式 靜態函式都不能使用this。實際上,成員函式預設第乙個引數為t const this。如 1classa 2 5 其中,func的原型在編譯器看來應該是 1intf...