函式指標的使用,以及使用函式指標的好處
函式指標是指向函式的指標變數。 因而“函式指標”本身首先應是指標變數,只不過該指標變數指向函式。程式在編譯時,每一個函式都有一個入口地址,該入口地址就是函式指標所指向的地址。很多c++泛型演算法以及linux庫函式經常見到函式指標的使用。。
函式指標的宣告:
bool (*pf)(int, int);
//pf指向一個函式,該函式的引數是兩個int,返回值是bool型別函式指標的初始化
例如有這樣一個函式:bool cmp(int a, int b);
pf = cmp//注意cmp形參及返回值應與宣告的的函式指標的型別匹配呼叫函式指標
bool b = pf(3,5);
等價於直接呼叫:bool b = cmp(3,5);函式指標使用的好處:
單單用以上的呼叫的方法使用函式指標,除了使程式變得晦澀難懂別無意義。包括很多例程只是在闡明函式指標的使用方法,完全不符合函式指標的使用場合。那到底為什麼還要使用函式指標呢!鬱悶了很久,雖沒完全理解的很深入,還是有所收穫,總的來說,函式指標有兩個方面的應用。
(1)把指標函式當作形參傳遞給某些具有一定通用功能的模組。並封裝成介面來提高程式碼的靈活性和後期維護的便捷性。
一個經典的例子是泛型演算法中的一個快速排序函式:
void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void *,const void*));
引數:
1 待排序陣列首地址
2 陣列中待排序元素數量
3 各元素的佔用空間大小
4 指向函式的指標,用於確定排序的規則
qsort設計時,底層開發者並不能確定呼叫者的需求,因此便採用函式指標的方法,在qsort內部通過函式指標呼叫傳遞過來的函式(這等同於在內部直接呼叫,但為了封裝成介面,供呼叫者使用,採用函式指標的方法更好,這種機制與形參傳遞變數類似)
這裡通過比較一個比較low的氣泡排序來說明一下qsort內部函式指標的實現機制:
#include<iostream>
using namespace std;
void sort(int arr[], int size, bool(*cmp)(int,int));
bool up(int a, int b);
bool down(int a, int b);
int main()
{
int arr[10];
for (int i = 0;i < 10;++i)
cin >> arr[i];
sort(arr, 10,down);
for (int i = 0;i < 10;++i)
cout << arr[i] << " ";
return 0;
}
void sort(int arr[],int size,bool(*cmp)(int,int))//簡單氣泡排序
{
int temp;
for (int i = 0;i < size-1; ++i)
{
for (int j = i;j < size-1;++j)
{
if (cmp(arr[i], arr[j + 1]))
{
temp = arr[i];
arr[i] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
bool up(int a, int b)
{
if (a > b)
return 1;
else
return 0;
}
bool down(int a, int b)
{
if (a > b)
return 0;
else
return 1;
}
呼叫者通過傳入相應的函式指標來決定排序的規則,這裡只是一個簡單的例子,真正的函式指標的使用可以將實現同一功能的很多個模組統一起來標識,這樣一來更容易後期的維護,系統結構更加清晰。或者歸納為:便於分層設計、利於系統抽象、降低耦合度以及使介面與實現分開。
該氣泡排序的通用性是不是稍微強大了一丟丟。。。。(其實此個例程中,也可以通過一個變數來決定使用什麼樣的排序規則,不過,我猜測,博大精深的庫中很多場合不是通過一個變數能解決的(僅僅猜測哈。。而且後期修改的話是不需要動sort函式框架的。。)
(2)另外,有些地方必須使用函式函式指標才能完成給定的任務,如linux系統中的非同步訊號中斷處理,當發生某一觸發訊號時,需要呼叫相應的處理函式,此時需要使用函式指標來實現。
void (*signal(int signum,void(* handler)(int)))(int);
引數一為訊號條件,第二個引數為一個函式指標,它所指向的函式需要一個整型引數,無返回值。
該函式的返回值也是一個函式指標,返回的指標所指向的函式有一個整型引數(一般不用)