C++學習筆記之函數指針
與數據項類似,函數也有地址。函數的地址是存儲其機器語言代碼的內存開始的地方。
一、函數指針的基礎知識
假設要設計一個名為estimate()的函數,估算編寫指定行數代碼所需時間,並且希望不同的程序員都使用該函數,並且該函數允許每個程序員提供自己的算法來估計時間。為實現這種目標,采用的機制是,將程序員要使用的算法函數地址傳給estimate(),必須完成以下工作:
獲取函數地址
聲明一個函數指針
用函數指針來調用函數
1.獲取函數地址
使用函數名(後面不跟參數)即可。如:think()是一個函數,則think就是該函數的地址。要將函數作為參數進行傳遞,必須傳遞函數名。
一定要注意區分傳遞的是函數的地址還是函數的返回值:
1 process(think); //傳遞函數think()的地址給process()
2 thought(think()); //傳遞函數think()的返回值給though()
2.聲明函數指針
聲明應指定指針所指向的函數的返回類型以及函數的特征標(參數列表),假設Pam編寫了一個估算時間的函數,其原型如下:
1 double pam(int); // 函數聲明
則正確的指針類型聲明如下:
1 double (*pf) (int);
2 // pf指向一個輸入一個int參數,返回一個double值得函數
可以看出,就是將函數聲明中的函數名替換為*pf, 於是pf就成為指向函數的指針,由指針的基本知識可以知道,(*pf)也是函數。
必須在聲明中用括號將*pf括起,否則如下:
1 double *pf(int);
這相當於聲明了一個函數pf,它的返回值是一個指向double的指針,與我們想要聲明的函數指針完全不是一碼事。
正確聲明pf之後,便可以將相應的函數地址賦給它:
1 double pam(int);
2 double (*pf)(int);
3 pf = pam;
現在指針pf就指向函數pam()了。再次強調pam()的特征標和返回類型必須與pf相同。
假設現在要將編寫的代碼行數和估算算法(如pam()函數)的地址傳遞給estimate(),原型如下:
1 void estimate(int lines, double (*pf)(int));
要讓estimate()使用pam()函數,需要將pam()的地址傳給它:
1 estimate(50, pam);
3.使用指針來調用函數
上面講過,(*pf)扮演的角色與函數名相同,因此使用(*pf)時,只需將它看作函數名即可:
1 double pam(int);
2 double (*pf)(int);
3 pf = pam;
4 double x = pam(4); // 用函數名調用函數
5 double y = (*pf)(5); // 用指針pf調用函數
但是,C++也允許像使用函數名那樣使用pf:
double y = pf(5); //與double y = (*pf)(5)效果一樣
為何pf與(*pf)等價呢?因為存在兩種看法,一種學派認為,由於pf是函數指針,而*pf是函數,因此應將(*pf)()用作函數調用;而另一種學派認為,由於函數名是指向該函數的指針,指向函數指針的行為應與函數名相似,因此應將pf()用作函數調用。看上去都是合理的說法,因此C++進行了折衷--兩種方法都正確,雖然在邏輯上相互沖突。
二、函數指針示例
復制代碼
1 /*函數指針示例*/
2 #include <iostream>
3
4 using namespace std;
5
6 //將會被調用的兩個函數的聲明
7 double betsy(int);
8 double pam(int);
9
10 //estimate()聲明
11 void estimate(int lines, double (*pf)(int));
12
13 int main()
14 {
15 int code;
16
17 cout << "請輸入代碼行數:";
18 cin >> code;
19 cout << "Betsy的評估結果:\n";
20 estimate(code, betsy);
21 cout << "Pam的評估結果:\n";
22 estimate(code, pam);
23 return 0;
24 }
25
26 double betsy(int lns)
27 {
28 return 0.05 * lns;
29 }
30
31 double pam(int lns)
32 {
33 return 0.03 * lns + 0.0004 * lns * lns;
34 }
35
36 void estimate(int lines, double (*pf)(int))
37 {
38 cout << lines << "行代碼將耗時 ";
39 cout << (*pf)(lines) << " 小時\n";
40 }