函式指標的好處、作用
C中函式指標的作用
專案中用到了很多封裝在struct中的函式指標,以前在MFC裡面經常用到則個作為回撥函式,還以為是微軟設計的特色呢。在網上查了一下它的用法,做個總結。
1)提供呼叫的靈活性。設計好了一個函式框架,但是設計初期並不知道自己的函式會被如何使用。比如C的”stdlib”中宣告的qsort函式,用來對數值進行排序。顯然,順序還是降序,元素誰大誰小這些問題,庫程式設計師在編寫qsort的時候不可能決定。這些問題是要在使用者呼叫這個函式的時候才能夠決定。那邊qsort如何保證通用性和靈活性呢?採用的辦法是讓函式的使用者來制定排序規則。於是呼叫者應該自己設計comparator函式,傳給qsort函式。這就在程式設計初期保證了靈活性。儘管使用函式指標使得程式有些難懂,但是這樣的犧牲還是值得的。
2)提供封裝效能。有點面向物件程式設計的特點。比如設計一個棧結構
typedef struct _c_stack{
int base_size;
int point;
int * base;
int size;
int (*pop)(struct _c_stack *);
int (*push)(int,struct _c_stack *);
int (*get_top)(struct _c_stack);
}c_stack;
在初始化完之後,使用者呼叫這個結構體上的pop函式,只需要s.pop(&s)即可。即使這個時候,工程內部有另外一個函式名字也叫pop,他們之間是不會發生名字上的衝突的。
原因很簡單,因為結構體中的函式指標指向的函式名字可能是
int ugly_stupid_no_one_will_use_this_name_pop(c_stack *)
,只是stack的使用者是不知道他在呼叫s.pop(&s),實際上起作用的是這樣一個有著冗長名字的函式。
函式指標這種避免命名衝突上的額外好處對於一些庫函式的編寫者是很有意義的,因為庫可能被很多的使用者在許多不同的環境下使用,這樣就能有效的避免衝突而保證庫的可用性。
一般的時候用不到,主要還是一個簡化結構和程式通用性的問題,也是實現面向物件程式設計的一種途徑。簡單的總結為:
1. 實現面向物件程式設計中的多型性
2. 回撥函式
舉兩個例子:
1. 你現在要實現一個檔案系統,但是檔案的介質有硬碟和軟盤,那麼它們各自的讀寫函式實現肯定是不一樣的。
好比
int a_write(char *data_stream, int LBA);
int b_write(char *data_stream, int LBA);
有一個結構體維護:
typedef int (*write_operation)(char* data, int LBA);
struct {
write_operation op;
...
} file_struct;
最後有一個寫函式:
int file_wirte(char *data_stream, int LBA)
{
return file_struct.op(data_stream, LBA);
}
2. Windows程式設計中的事件handle函式,即回撥函式,在事件佇列都是一個函式指標來儲存的:
typedef void (*event_handler) (unsigned int para1, unsigned int para2);
struct event {
unsigned int ev_id;
event_handler handler;
};
struct event event_queue[MAX_EVENT_SIZE];
程式可以通過掃描這個事件佇列來獲取每個事件對應的處理函式,然後呼叫它,即為回撥函式。
舉報▼|2012-05-11 13:39823807 | 分類:C/C++ | 瀏覽1428次
使用函式指標的好處在於,可以將實現同一功能的多個模組統一起來標識,這樣一來更 容易後期的維護,系統結構更加清晰。或者歸納為:便於分層設計、利於系統抽象、降低耦合度以及使介面與實現分開 我是初學者,不明白這段話什麼意思,求解釋2012-05-11 14:27提問者採納
你上面那一段話,對於初學者來說確實坑爹,說的像什麼官方話語,我看著也就只能理解個模糊大概。 先給你舉個例子吧,函式指標的寫法 int *p; int a; p=&a; //這是一般整型指標 #include <iostream> using namespace std; int arr(int a,int b){return 0;}//比如說是函式1 int brr(int a,int b){return 1;}//比如說是函式2 int main() { int (*frr)(int,int); //這裡就是函式指標 frr =arr; //它可以指向arr cout<<frr(1,2)<<endl; frr=brr;//也可以指向brr,只需要改改指向的物件,就可以操作不同的函式 cout<<frr(1,2)<<endl; return 0; }評論|120 按預設排序|按時間排序
其他2條回答
2012-05-11 14:57copylegend|五級好吧,假設你已經知道函式指標的寫法和用法。 那麼那段話的意思就是, 你有了一隻手,可以用來裝備並切換武器打怪,比如可以裝備刀子,或者裝備棍子。當你的武器只有一種或者比較少的時候,可能這隻手切換武器的功能不常用到。當到了後期,你的武器多了,那你因為有了這隻能裝備並切換武器的手,而可以更有效率的打怪。 OVER評論(1)|70 2012-05-12 11:20劉嘉璠|四級
上面的話是有道理的。只是,要真的體會這些名詞,需要你親歷躬行,一個“百度知道”是很難讓你真正體會並理解的。國人一些教科書也不負責任,人云亦云的說這些話,但很少能透徹講解。我小試一下。 1. 便於分層設計:函式指標是引用,是間接層,或曰隔離層。它輸出到上層,給上層使用者用。函式實體是實現,在下層,給開發者用,實現者(軟體工程師)關注。這就是簡單的分層的概念了。上層使用者想讓一個函式所做的東西會變化時,我們只需要改變底層實現,並用函式指標指向新的實現就行了。 再精煉一下分層:分層的核心是對介面進行設計和實現。函式指標的作用就是提供不同實現的統一介面。 2. 利於系統抽象:只有存在多個類似的實體需要模擬、操作或控制時(這種情況很多)才需要抽象。多個類似的實體就是物件,抽象的結果就是類。在C裡邊,可以用函式指標陣列完成這種抽象。如, fopen 就是一個例子。他可以開啟檔案。C裡面將磁碟檔案、串列埠、USB等諸多裝置抽象為檔案。 3. 降低耦合度以及使介面與實現分開:第1條中的解釋已經說明了這一點。 再具體一下: 我曾搭建過一個嵌入式平臺。其中的裝置操作(硬體驅動)採用了多組函式指標資料,並進行了簡單的封裝,其結果是: 業務軟體使用函式指標陣列的封裝函式訪問裝置。這個封裝可展示為: int DevOpen(char *strDevName); int Write(int DevID, char* DataFrom, int StartDevAddr, int DataLong); int Read(int DevID, char* DataTo, int StartDevAddr, int DataLong); int DevClose(int DevID); 這組抽象出來的函式,是一組語義清晰且穩定的上層介面,為上層的業務開發團隊使用。底層的驅動層,各自實現自己的裝置開啟、讀、寫及關閉程式碼,然後,註冊自己的裝置到系統列表裡。上層業務接可以使用了。期間的耦合在這裡: int Write(int DevID, char* DataFrom, int StartDevAddr, int DataLong) { /* Error detecting. */ return DevWrite[ DevID ]( char* DataFrom, int StartDevAddr, int DataLong ); } 其中,DevWrite[ DevID ]就是一個函式指標陣列: int (*DevWrite)[ MAX_DEV_NUM ]( char*,int,int ) = {0}; 裡面放的就是多個裝置的寫的操作。其中包括:UART,RTC,WatchDog。EEPROM,DigitalInput,DigitalOutput,Key,LCD,LED。 好了。說的太多了。如需要學習,可郵件[email protected]。 但願對你有所幫助。
舉報▼|2008-02-04 14:2413152448536 | | 瀏覽2313次
書上給了個例子,但還是看不懂有什麼好處? #include<stdio.h> float add(float x,float y) {return (x+y);} float sub(float x,float y) {return (x-y);} float mul(float x,float y) {return (x*y);} float div(float x,float y) {return (x/y);} float result(float x,float y,float(*pf)(float,float)) { float s; s=(*pf)(x,y); return s; } void main() { float a,b,s; char op; printf(""please select your operation (input +,-,*or/)\n"); scanf("%c",&op); printf("please input the two operand\n"); scanf("%f %f",&a,&b); switch(op) { case '+':s=result(a,b,add);break; case '-':s=result(a,b,sub);break; case '*':s=result(a,b,mul);break; case '/':s=result(a,b,div);break; } printf("the operation is :%f%c%f=%f\n",a,op,b,s); }2008-02-04 23:02提問者採納
靈活。 實際上我覺得如果作引數不用指標的話,還真不知道怎麼解決。 引數傳遞一般就是傳值和傳址兩種方式,作為函式的話,好像都想不出怎麼傳值。 我理解所謂指向函式的指標就是這個函式的入口地址。直接就跳轉到那個地址去執行了。