=========================引子=========================
我們都知道,數(shù)組名就是指向數(shù)組第一個(gè)元素的常量指針(詳見《數(shù)組拾遺》)。同理,對(duì)于一個(gè)函數(shù)而言,函數(shù)名也是指向函數(shù)第一條指令的常量指針。而編譯器要做的就是在程序編譯之后,為每個(gè)函數(shù)分配一個(gè)首地址,即該函數(shù)第一條指令的地址。一般情況下,我們可以用一個(gè)指針來保存這個(gè)地址,而這個(gè)指針就是函數(shù)指針,該指針可以看作是它指向函數(shù)的別名,所以我們可以用該指針來調(diào)用這個(gè)函數(shù)。
=========================函數(shù)指針的聲明方法=========================
type (*func)(type &,type &)
|
該語句聲明了一個(gè)指針func,它指向了一個(gè)函數(shù),這個(gè)函數(shù)帶有了2個(gè)type型參數(shù)并返回一個(gè)type的值。
p.s. type類型可以被看成是int啊或者是floast等C++的類型。
=========================注意事項(xiàng)=========================
- 一個(gè)指向函數(shù)的指針必須確保該函數(shù)被定義且分配了內(nèi)存,否則它將指向一個(gè)空地址,這個(gè)可是大忌!
- 特別注意第一個(gè)括號(hào)的位置。如果我們不寫括號(hào),如下:
這就不是一個(gè)指向函數(shù)的指針了,而是聲明了一個(gè)函數(shù),該函數(shù)返回一個(gè)type類型的指針
=========================函數(shù)指針應(yīng)用示例=========================
我們以這樣一個(gè)程序?yàn)槔涸摮绦虻墓δ苁怯?jì)算三角形的矩形的面積。其中,三角形的長(zhǎng)和高,矩形的長(zhǎng)和寬由用戶自己輸入,并且我們提供一個(gè)交換函數(shù),用來交換用戶輸入的長(zhǎng)和高(寬)。
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<< "自定義長(zhǎng)寬(高)為:\n" ;
cout<< "長(zhǎng)為:" ;
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); 設(shè)定長(zhǎng)、寬或高(1); 三角形面積(2); 矩形面積(3); 交換長(zhǎng)寬或高(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<< "請(qǐng)按規(guī)矩出牌!" <<endl;
}
}
return 0;
}
|
在這個(gè)例子中,我們采用普通函數(shù)大方法,來輸出三角形和矩形的值,輸出如下:

下面,我們來看看如果采用函數(shù)指針,效果會(huì)是怎樣?由于我們?cè)谇懊娣治鲞^了,函數(shù)指針就是一個(gè)指向函數(shù)的指針。那么我們?cè)谡{(diào)用函數(shù)的時(shí)候,就可以運(yùn)用指針
來調(diào)用這個(gè)函數(shù)。而且,周所周知,指針可以作為一個(gè)函數(shù)的參數(shù),那么函數(shù)指針也不應(yīng)該例外。這樣就好了,我們可以講函數(shù)的指針作為函數(shù)參數(shù)來調(diào)用。對(duì)于一
個(gè)普通要調(diào)用指針的函數(shù)而言,聲明應(yīng)該是這個(gè)樣子的:
type func(type*, type , type)
|
那么由上面這句話就可以看出來,這個(gè)函數(shù)func的第一個(gè)參數(shù)就是一個(gè)指向type類型的指針,而后面兩個(gè)參數(shù)就是兩個(gè)類型為type的形式參數(shù)。結(jié)合本文一開始所列的函數(shù)參數(shù)的聲明格式,那么函數(shù)指針作為函數(shù)參數(shù)的一般形式就是:
type func(type(*p)(type &, type &),type &,type &);
|
該函數(shù)func有3個(gè)參數(shù),第一個(gè)參數(shù)為type(*p)(type &, type &),這就是一個(gè)函數(shù)指針,他指向一個(gè)帶有兩個(gè)type類型的參數(shù)并且返回type值的函數(shù),另外兩個(gè)參數(shù)都是type類型的引用。
這樣一來,我們就可以利用函數(shù)指針把函數(shù)作為另外一個(gè)函數(shù)的參數(shù)調(diào)入到那個(gè)函數(shù)中使用了。對(duì)于上面這個(gè)例子,我故意把所有的函數(shù)都生聲明為帶有兩個(gè)
double類型的變量,且返回值均為double。這樣做的原因只是為了讓后面我們?cè)诶煤瘮?shù)指針調(diào)用的時(shí)候方便一些。因?yàn)槲覀冎恍枰獙⒑瘮?shù)指針聲明成
與之想匹配的函數(shù)就行了。從上面這個(gè)例子看出,它麻煩就麻煩在每次輸出的時(shí)候都需要在case語句中進(jìn)行操作,那么我們能不能利用函數(shù)指針將其一并簡(jiǎn)化到
print函數(shù)中呢,請(qǐng)看下例:
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<< "自定義長(zhǎng)寬(高)為:\n" ;
cout<< "長(zhǎng)為:" ;
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); 設(shè)定長(zhǎng)、寬或高(1); 三角形面積(2); 矩形面積(3); 交換長(zhǎng)寬或高(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<< "請(qǐng)按規(guī)矩出牌!" <<endl;
}
}
return 0;
}
|
在例2中,我們采用了函數(shù)指針的方式,可以看到,在case語句中只需要制定每個(gè)函數(shù)指針?biāo)赶虻暮瘮?shù)是什么,那么在print函數(shù)中,我們就可以調(diào)用這個(gè)函數(shù)了。輸出如下所示:

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