2012-11-12 26 views
0

我的一位老師用這個類型聲明:使用的typedef來包裝功能

typedef void (*SortFunction)(int a[], int n); 

創建一個類型,它可以容納一個指向函數 和可用於以後調用該函數在程序。

我也知道,要傳遞一個函數,你必須 括號包住函數名和函數名後包裹在括號中的功能的 參數的參數以及像這樣

function someFunction((anotherfunction)(type arg1, type arg2,...)){ 
    ... 
} 

我想知道爲什麼你必須像這樣在括號中包裝一個函數?這是大多數C++編譯器的內置函數,還是我們程序員使用 以簡化代碼中的參數的一個竅門?另外,爲什麼需要引用typedef語句中的「SortFunction」 ,爲什麼用於使用SortFunction的變量只能保存函數而不是指向它?

回答

1

函數參數沒有什麼特別之處。當你聲明一個函數指針(如局部變量,全局變量,類成員變量,函數參數類型定義,等等),它一直宣稱,像這樣:

return_type (*var_name)(T1 param1, T2 param2, /* etc. */); 
//   ^
//   | 
// This * is very important! 

哪裏var_name是函數指針的名字變量。圍繞*var_name需要括號的原因是由於運算符的優先級:沒有括號,*(表示某個指針)會與該函數的返回類型相匹配,相反,您會得到類似於返回類型int*(指針到int)而不是普通的int

您不能將函數作爲參數傳遞,因爲函數不是C和C++中的第一類對象。傳遞函數的唯一方法是傳遞一個指向函數的指針。

0

這是一個語法問題。你的第一個typedef定義了一個類型,它是一個函數,它接收一個向量int和一個int並且什麼都不返回(void)。

SortFunction類型的變量概念上與其他變量一樣,儘管它指向某種功能。優點是可以更改指向的功能和/或動態調用該功能。

0

我想知道的是爲什麼你必須在這樣的括號中包裝一個函數?

因爲必須有某種方法來識別指向編譯器(或者說,解析器)的函數指針,並且這種方式看起來和任何指針一樣好。在C++ 11的土地上,你可以用這個代替:std::function<void(std::array<int>&)>

這是大多數C++編譯器的函數嗎?或者它只是我們程序員用來啓用函數作爲我們代碼中的參數的一個技巧?

函數指針需要一點額外的魔力,如果沒有編譯器支持,它們會非常非常不方便使用。我也有理由相信,編程本質上,幾乎所有的編程技巧都是編譯器的功能!

也,爲什麼在typedef語句「SortFunction」需要被引用,爲什麼不能變,你用它來使用SortFunction牽住的函數,而不是指向它?

嗯。不完全確定你的意思。你的意思是「爲什麼這需要成爲typedef ......爲什麼我不能在我的函數參數」中寫出整個函數指針原型?因爲你可以:

void foo(void(*funcptr)()) {} 

如果你的意思是「爲什麼函數指針必須在一個功能點具有聯代碼而不是」然後,你需要C++ 11 lambda表達式和:

#include <iostream> 
#include <functional> 

void foo(std::function<void(void)> bar) { bar(); } 

int main(int argc, char* argv[]) 
{ 
    foo([]() { std::cout << "hi!" << std::endl; }); 
} 

(再次,特殊的語法需要lambda表達式,[](){},只是告訴什麼是要去解析器)

+0

請注意,如果我閱讀最新的C++ 11標準權限,則上下文無關的lambdas可以隱式轉化爲函數指針。 – Yakk

+0

@Yakk你可能是對的,但我不得不支持這兩個編譯器。但是,它們都沒有特別強大的C++ 11支持。 – Rook

+0

是的 - 我相信這是在標準化週期後期加入的。或者,也許它沒有被添加,只是考慮... – Yakk

0

「我也知道,要傳遞一個函數作爲參數,你必須包裝在parenthe函數名sis ...「你」認識「不正確。

爲了傳遞函數指針作爲參數,您不必將名稱包裝在圓括號中。例如,這將完全正常工作

void foo(int i) { 
} 

void bar(void f(int)) { 
    f(5); 
} 

int main() { 
    bar(); 
} 

在上述例子中功能bar接收函數指針foo作爲參數,並通過該指針調用foo,傳遞5作爲參數。如您所見,參數聲明中的函數名稱f而不是包含在括號中。

在這種情況下,參數f的類型實際上是一個指針函數,即使它沒有顯式聲明爲指針。在函數參數聲明中使用函數類型時,編譯器會自動用函數指針類型「隱式」替換它。

如果你想明確地使用函數指針類型,您必須聲明bar作爲

void bar(void (*f)(int)) { 
    f(5); 
} 

在這種情況下(*f)括號是必要的,以確保*將得到勢必f,而不是void。沒有括號,void *f(int)聲明將代表「功能返回void *」而不是所需的「返回void函數的指針」。