2011-08-01 51 views
7

typedef int (&rifii) (int, int)將用於什麼?C++語法/語義問題:引用函數和typedef關鍵字

這個「聲明」之前的typedef是做什麼的? 我想認爲這是

typedef (int (&rifii) (int, int)) [new name] 

但[新名稱]是不存在一樣,如果你對下面的語法做

typedef int INTEGER; 

類似的問題:

typedef void (*PF)(); 

PF edit_ops[ ] = { &cut, &paste, &copy, &search }; 
PF file_ops[ ] = { &open, &append, & close, &write }; 

PF* button2 = edit_ops; 
PF* button3 = file_ops; 

button2[2](); 

什麼typedef是否允許?難道使得它,這樣你就不必鍵入:

void (*PF)(); 
(void (*PF)()) edit_ops[ ] = { &cut, &paste, &copy, &search }; 
(void (*PF)()) file_ops[ ] = { &open, &append, & close, &write }; 

(void (*PF)())* button2 = edit_ops; 
(void (*PF)())* button3 = file_ops; 

如果是發生了什麼的第二部分([你想要什麼])中的typedef像:

typedef [what you have -- (FP)] [what you want] 

澄清此事不勝感激。

+0

http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples -hints-and-tips-plea – vines

+0

這個問題是類似的,我在發帖之前仔細查看了相關主題,但是我的問題是特定的,我無法從其他帖子推斷出答案。 –

回答

16

Typedef不能像typedef [type] [new name]那樣工作。 [new name]部分並不總是結束。

你應該這樣看待它:如果[some declaration]聲明一個變量,typedef [same declaration]會定義一個類型。

例如:

  • int x;聲明瞭一個名爲x int類型的變量 - >typedef int x; 定義一種類型x作爲INT。
  • struct { char c; } s;定義了一個結構類型爲s的變量 - >typedef struct { char c; } s;將類型s定義爲某個結構類型。
  • int *p;聲明瞭一個名爲p類型指針的變量int - > typedef int *p;定義了一個類型p作爲指向int的指針。

並且:

  • int A[];聲明瞭一個名爲整數數組A - >typedef int A[];聲明一個類型A作爲整數數組。
  • int f();聲明一個名爲f - >typedef int f();的函數聲明一個函數類型f返回一個int並且不帶任何參數。
  • int g(int);聲明一個函數名g - >typedef int g(int);聲明一個函數類型g返回一個int並取一個int。

順便說一句:請注意,所有函數參數都在新名稱之後!由於這些類型也可能很複雜,所以在[新名稱]之後可能會有很多文本。可悲的是,但是的確如此。

但是那些功能不正確指針還有,只是函數類型。我不確定C或C++中是否存在函數類型,但作爲解釋中的中間步驟很有用。

要創建一個真正的函數指針,我們必須給名稱添加'*'。其中,可悲的是,有錯誤的優先級:

  • typedef int *pf();聲明的函數型PF爲返回INT *。糟糕,這不是預期的。

因此,使用()來組:

  • typedef int (*pf)();聲明的函數指針類型PF爲返回一個int和不接受參數。
  • typedef int (&rf)();聲明一個函數引用類型rf返回一個int並且不帶任何參數。

現在讓我們來看看你的例子,並回答您的問題:

typedef int (&rifii) (int, int);聲明的函數引用類型rifii爲返回一個int,並採取兩個int參數。

顯然(?)button2[2]();將會撥打copy();

的typedef不正確的語法是很難正確地寫沒有編譯器和硬盤即使有編譯器來閱讀:

void (*edit_ops[])() = { &cut, &paste, &copy, &search }; 
void (*file_ops[])() = { &open, &append, & close, &write }; 

void (**button2)() = edit_ops; 
void (**button3)() = file_ops; 

button2[2](); 

這就是爲什麼每個人都使用函數指針時喜歡的typedef。

閱讀時,找到開始閱讀的地方。儘可能多地閱讀正確的內容,但通過()觀察分組。然後儘可能多地閱讀,再次受限於分組()。完成()中的所有內容後,從右邊開始閱讀,然後再閱讀。

應用於void (*edit_ops[])(),這意味着

  1. edit_ops是 (轉到右側)
  2. 陣列 (命中的組的端部,所以向左轉)
  3. 的指針 (分組的末尾)
  4. 採取 一個函數(解析()向右)
  5. 沒有argume NTS (向左走)
  6. 返回一個空

對於專家: 爲了使它更加複雜,參數可以有名字(這將被忽略),所以它甚至可能是很難找到從哪裏開始解析!例如。 typedef int (*fp)(int x);有效且與typedef int (*fp)(int);一樣有名稱甚至可以在它們周圍有():typedef int (*fp)(int (x));但正如我們所看到的,參數名稱可以省略,因此即使允許以下條件:typedef int (*fp)(int());。這仍然是一個函數指針,它接受一個int並返回一個int。如果你想讓你的代碼真的很難閱讀...

+0

你的解釋是幫助。澄清:typedef void(* PF)();聲明一個類型(* PF),它被定義爲一個函數指針,它接受0個參數並且什麼都不返回。所以現在我們有一個類型PF,如果我們可以在我們的表達式中使用它(我可能會聲明語句),比如PF edit_ops [] = {。沒有定義「新類型」,我們使用void(* edit_ops [])()= {...}。這就是說我們正在創建一個函數指針數組,它可以是...?這個表達式的類型是一個函數指針嗎? –

+0

@Matthew:是的,'void(* edit_ops []()= {...};定義一個函數指針數組,並用值'cut','paste','copy'和'search'來初始化這個數組。 void(** button2)()= edit_ops;'聲明一個指向該數組的第零個元素的指針。 'button2 [2]();'使用數組的第三個元素並調用它指向的函數。這恰好是「複製」。 – Sjoerd

+0

@Matthew:在你的第一句話中,'typedef void(* PF)()'聲明瞭一個'PF'類型,* not *'(* PF)'。 'PF'已經是一個指針了。最後一個語句void(* x [])()= ...'聲明'x'是一個函數指針數組。 –

-1

編輯:對不起,首先回答沒有初始化fcn ptr。

typedef int(& rifii)(int,int)允許您聲明通過引用返回int並將兩個int作爲參數的函數指針。

rifi x,y,z; 

int &ret_an_int_ref(int p1, int p2) { 
    static int retval=0; 
    if(p1 > p2) retval = p1*p2; 
    return retval; 
} 

    x = ret_an_int_ref; 
    y = ret_an_int_ref; 

int & an_int_ref = x(1,2); 
int & another_int_ref=y(3,4); 

z = x; 

z(1,2); // will give the same answer as x(1,2); 
+0

那麼rifi現在是一種類型?變量x,y和z是那種類型?據Bjarne說,從函數返回一個參考是一種罪過,所以我假設我永遠不會看到這個? –

+0

我不能100%肯定地說rifi是否是一個「類型」,希望上師能夠參與進來。它的行爲就像一個類型,可以像類型一樣傳遞,並可能用作模板參數。你很可能永遠不會看到這一點,但有時對於複雜的數據類型,最好由ref返回。並且operator =應該總是通過ref返回,以便像A = A這樣的啞語不會導致seg錯誤。 –

+0

該函數不返回對int的引用,但是它是對返回(普通)int的函數的引用。你的版本應該是'typedef int&(rifii)(int,int);' – Sjoerd

5

此:

typedef int (&rifii) (int, int); 

創建名爲rifii的typedef,這是一個函數,它有兩個整數和返回一個整數。這是用於聲明函數typedefs的typedef語法。所以,如果你有一個函數:

int SomeFunc(int a, int b); 

您可以將其存儲在該類型定義:

rifii varName = SomeFunc; 

後來稱之爲:

varName(1, 3); 

所以,如果你申報的rifii陣列,你所擁有的是一系列對所有具有相同簽名的函數的引用。你的typedef是一個指針函數,它不接受任何參數,也不返回任何內容,所以它們的數組是不帶參數且不返回任何內容的函數的數組。基本上,由於C/C++函數命名的奇怪,typedef名稱(您正在爲其創建typedef的名稱)位於函數類型的中間。這很奇怪,但你已經習慣了。