|
=========================引子=========================
我們都知道,數(shù)組名就是指向數(shù)組第一個元素的常量指針(詳見《數(shù)組拾遺》)。同理,對于一個函數(shù)而言,函數(shù)名也是指向函數(shù)第一條指令的常量指針。而編譯器要做的就是在程序編譯之后,為每個函數(shù)分配一個首地址,即該函數(shù)第一條指令的地址。一般情況下,我們可以用一個指針來保存這個地址,而這個指針就是函數(shù)指針,該指針可以看作是它指向函數(shù)的別名,所以我們可以用該指針來調用這個函數(shù)。
=========================函數(shù)指針的聲明方法=========================
type (*func)(type &,type &)
|
該語句聲明了一個指針func,它指向了一個函數(shù),這個函數(shù)帶有了2個type型參數(shù)并返回一個type的值。
p.s. type類型可以被看成是int啊或者是floast等C++的類型。
=========================注意事項=========================
- 一個指向函數(shù)的指針必須確保該函數(shù)被定義且分配了內存,否則它將指向一個空地址,這個可是大忌!
- 特別注意第一個括號的位置。如果我們不寫括號,如下:
這就不是一個指向函數(shù)的指針了,而是聲明了一個函數(shù),該函數(shù)返回一個type類型的指針
=========================函數(shù)指針應用示例=========================
我們以這樣一個程序為例:該程序的功能是計算三角形的矩形的面積。其中,三角形的長和高,矩形的長和寬由用戶自己輸入,并且我們提供一個交換函數(shù),用來交換用戶輸入的長和高(寬)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include <iostream>
using namespace std;
double triangle_area(double &x,double &y);
double rectangle_area(double &x,double &y);
double swap_value(double &x,double &y);
double set_value(double &x,double &y);
double print_area(double &x,double &y);
double triangle_area(double &x,double &y)
{
return x*y*0.5;
}
double rectangle_area(double &x,double &y)
{
return x*y;
}
double swap_value(double &x,double &y)
{
double temp;
temp=x;
x=y;
y=temp;
return 0.0;
}
double print_area(double &x,double &y)
{
cout<<"執(zhí)行函數(shù)后:\n";
cout<<"x="<<x<<" y="<<y<<endl;
return 0.0;
}
double set_value(double &x,double &y)
{
cout<<"自定義長寬(高)為:\n";
cout<<"長為:";
cin>>x;
cout<<"寬或者高為:";
cin>>y;
return 0.0;
}
int main()
{
bool quit=false;
double a=2,b=3;
char choice;
while(quit==false)
{
cout<<"退出(q); 設定長、寬或高(1); 三角形面積(2); 矩形面積(3); 交換長寬或高(4)."<<endl;
cin>>choice;
switch(choice)
{
case 'q':
quit=true;
break;
case '1':
set_value(a,b);
print_area(a,b);
break;
case '2':
print_area(a,b);
cout<<"三角形的面積為:\t"<<triangle_area(a,b)<<endl;
break;
case '3':
print_area(a,b);
cout<<"矩形的面積為:\t"<<rectangle_area(a,b)<<endl;
break;
case '4':
swap_value(a,b);
print_area(a,b);
break;
default:
cout<<"請按規(guī)矩出牌!"<<endl;
}
}
return 0;
}
|
在這個例子中,我們采用普通函數(shù)大方法,來輸出三角形和矩形的值,輸出如下:

下面,我們來看看如果采用函數(shù)指針,效果會是怎樣?由于我們在前面分析過了,函數(shù)指針就是一個指向函數(shù)的指針。那么我們在調用函數(shù)的時候,就可以運用指針
來調用這個函數(shù)。而且,周所周知,指針可以作為一個函數(shù)的參數(shù),那么函數(shù)指針也不應該例外。這樣就好了,我們可以講函數(shù)的指針作為函數(shù)參數(shù)來調用。對于一
個普通要調用指針的函數(shù)而言,聲明應該是這個樣子的:
type func(type*, type , type)
|
那么由上面這句話就可以看出來,這個函數(shù)func的第一個參數(shù)就是一個指向type類型的指針,而后面兩個參數(shù)就是兩個類型為type的形式參數(shù)。結合本文一開始所列的函數(shù)參數(shù)的聲明格式,那么函數(shù)指針作為函數(shù)參數(shù)的一般形式就是:
type func(type(*p)(type &, type &),type &,type &);
|
該函數(shù)func有3個參數(shù),第一個參數(shù)為type(*p)(type &, type &),這就是一個函數(shù)指針,他指向一個帶有兩個type類型的參數(shù)并且返回type值的函數(shù),另外兩個參數(shù)都是type類型的引用。
這樣一來,我們就可以利用函數(shù)指針把函數(shù)作為另外一個函數(shù)的參數(shù)調入到那個函數(shù)中使用了。對于上面這個例子,我故意把所有的函數(shù)都生聲明為帶有兩個
double類型的變量,且返回值均為double。這樣做的原因只是為了讓后面我們在利用函數(shù)指針調用的時候方便一些。因為我們只需要將函數(shù)指針聲明成
與之想匹配的函數(shù)就行了。從上面這個例子看出,它麻煩就麻煩在每次輸出的時候都需要在case語句中進行操作,那么我們能不能利用函數(shù)指針將其一并簡化到
print函數(shù)中呢,請看下例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #include <iostream>
using namespace std;
double triangle_area(double &x,double &y);
double rectangle_area(double &x,double &y);
double swap_value(double &x,double &y);
double set_value(double &x,double &y);
double print_area(double(*p)(double&,double&), double &x,double &y);
double triangle_area(double &x,double &y)
{
cout<<"三角形的面積為:\t"<<x*y*0.5<<endl;
return 0.0;
}
double rectangle_area(double &x,double &y)
{
cout<<"矩形的面積為:\t"<<x*y<<endl;
return 0.0;
}
double swap_value(double &x,double &y)
{
double temp;
temp=x;
x=y;
y=temp;
return 0.0;
}
double print_area(double(*p)(double &x,double &y), double &x,double &y)
{
cout<<"執(zhí)行函數(shù)前:\n";
cout<<"x="<<x<<" y="<<y<<endl;
p(x,y);
cout<<"函數(shù)指針傳值后:\n";
cout<<"x="<<x<<" y="<<y<<endl;
return 0.0;
}
double set_value(double &x,double &y)
{
cout<<"自定義長寬(高)為:\n";
cout<<"長為:";
cin>>x;
cout<<"寬或者高為:";
cin>>y;
return 0.0;
}
int main()
{
bool quit=false;
double a=2,b=3;
char choice;
double (*p)(double &,double &);
while(quit==false)
{
cout<<"退出(q); 設定長、寬或高(1); 三角形面積(2); 矩形面積(3); 交換長寬或高(4)."<<endl;
cin>>choice;
switch(choice)
{
case 'q':
quit=true;
break;
case '1':
p=set_value;
print_area(p,a,b);
break;
case '2':
p=triangle_area;
print_area(p,a,b);
break;
case '3':
p=rectangle_area;
print_area(p,a,b);
break;
case '4':
p=swap_value;
print_area(p,a,b);
break;
default:
cout<<"請按規(guī)矩出牌!"<<endl;
}
}
return 0;
}
|
在例2中,我們采用了函數(shù)指針的方式,可以看到,在case語句中只需要制定每個函數(shù)指針所指向的函數(shù)是什么,那么在print函數(shù)中,我們就可以調用這個函數(shù)了。輸出如下所示:

在該程序的第61行,我們就聲明了一個函數(shù)指針??梢钥吹?,在程序的case語句中,我們只需要把這個函數(shù)指針傳遞到print_area()函數(shù)里面就
可以了。這樣十分方便。而且我們可以看到,其實只要在print_area()中,即程序的第38行加上對這個函數(shù)指針的調用,我們就可以利用指針所指向
的函數(shù)了。這十分方便。但是有幾個小知識點應該注意一下:
- 聲明函數(shù)指針時,其返回值,參數(shù)個數(shù),參數(shù)類型應該與需要它指向的函數(shù)保持一致;否則,編譯器會報錯,無法從“***”轉換到“***”;
- 利用函數(shù)指針只想某個函數(shù)的時候,我們只用,也只能給出該函數(shù)的函數(shù)名,不能把參數(shù)一并給出了。比如說在上例中,如果我們把程序的第84行改成:
那么編譯器會報錯: func_pointer.cpp(84) : error C2440: “=”: 無法從“double”轉換為“double (__cdecl *)(double &,double &) 這個錯誤的原因就是因為我們忘記了在文章一開頭所講的函數(shù)指針的一句話:函數(shù)名也是指向函數(shù)第一條指令的常量指針。因為函數(shù)指針就是指向其函數(shù)的地址的,那么我們就應該利用函數(shù)指針來指向函數(shù)名就可以了。
=========================補充一點哈 ^_^=========================
如果你認為上面所訴的函數(shù)指針的聲明格式有點羅嗦,那么我們也可以利用typedef來簡化聲明和定義的操作。比如說在上例2的第61行,那么長一串。我們完全可以在在程序一開始利用typedef來代替:
typedef double (*vp)(double &,double &);
|
這樣一來,我們就可以把程序的第61行簡化成:
而且,我們在聲明和定義print_area()函數(shù)的時候,就可以程序的第10行和第33行換成:
double print_area(vp,double &x,double &y);
double print_area(vp p, double &x,double &y)
|
好了,關于函數(shù)指針就總結到這里,更多內容請關注“唯一的天空”其他內容,謝謝 ^_^。
敬請期待:博文《函數(shù)指針及其的運用(下)——函數(shù)指針的擴展》
|