1
四,typedef关键字、函数指针与重载函数五、函数指针构成的数组
2
四,typedef关键字、函数指针与重载函数左边声明函数指针别名 VFI,PFD,右边定义函数指针
vfi,pfd。
typedef void (*VFI)(int);
void (*vfi)(int);
typedef double* (*PFD) (double*,double*);
double* (*pfd)(double*,double*);
PFD是类型属性为 double* (*)(double*,double*)的别名,VFI是类型属性为 void (*)(int)的别名。在函数指针类型声明语句中去掉 typedef关键字得到函数指针定义语句。
3
函数指针的类型别名在返回函数指针的函数上有独到之处。可用函数指针的类型别名定义函数指针。 例如:
PFD pf,pfd,pmax; VFI vfi,pvfi;
重载函数通过函数名与形参类型列表被编译器细分为不同的函数,重载函数的入口地址是唯一的,可以定义指向重载函数某个版本的函数指针。
根据函数指针的类型属性与其所指向的函数名的类 型属性进行匹配。
4
[例 ] 函数指针与重载函数,函数指针根据重载函数名的入口类型匹配
#include<stdio.h>
double& max(double& x,double& y){printf("&");
return x>y?x:y; }
double* max(double* x,double* y){printf("*");
return *x>*y?x:y; }
double* (*pmax)(double*,double*) =max;
double& (*rmax)(double&,double& )=max;
5
void main(void)
{ const char* fmt="max(x=%2.0f,y=%2.0f)=%2.0f; " ;
double x=10,y=10;
rmax (x,y)+=10;
printf (fmt,x,y,(*rmax)(x,y));
*pmax(&x,&y)+=10;
printf (fmt,x,y,*(*pmax)(&x,&y));
typedef double* (*PFD)(double*,double*);
rmax=(double&(*)(double&,double&))(PFD)max;
*(( PFD)rmax)(&x,&y)+=10;
printf (fmt,x,y,*(*(( PFD)rmax))(&x,&y));}
6
//输出,&&max(x=10,y=20)=20;
**max(x=10,y=30)=30;
**max(x=10,y=40)=40
说明,函数名 max对应两个版本,类型属性为
double& (*)(double&,double&)的引用版本和
double* (*)(double*,double*)指针版本,类型转 ( PFD)max
表示取指针版本的函数地址,
(double&(*)(double&,double&))(PFD)max表示将这个地址转换为目标函数指针 rmax的类型属性。
调用 *(( PFD)rmax)(&x,&y)表示将函数指针恢复到原来的状态,即启动指针版本的 max函数。这种类型转换与复原技术在 MFC消息映射中多次采用。
7
一般地,设源函数指针 pfsrc的类型属性为,
type (*)(T1,T2),目标函数指针 pfdst的类型属性为,
type (*)(Ti,Tj),则函数指针直接的映射格式为:
pfdst= (type (*)(Ti,Tj)) pfsrc;
如果存在函数为 f的重载函数,它们的类型属性分别为
T1 (*)(T1,T2),T3 (*)(T3,T4),为了鉴别函数重载,映射关系细致地处理为,
pfdst= (type (*)(Ti,Tj)) (T1 (*)(T1,T2))f;
//取函数 f(T1,T2)的地址并类型转换
pfdst= (type (*)(Ti,Tj)) (T3 (*)(T3,T4))f;
//取函数 f(T3,T4) 的地址并类型转换
8
五、函数指针构成的数组数组是同类型元素构成的数据集合,如果这些元素恰好是函数指针,则形成函数指针数组,其定义格式为:
type (*ppf[m])(T1,T2 );
类型( *函数指针数组名 [m]) (类型 1,类型 2);
其中 m是静态确定的整数。函数指针数组名 ppf具有
type (**)(T1,T2)的类型属性,ppf的每一个元素是类型属性
type (*)(T1,T2)的函数指针。
对于声明和定义语句,
typedef type (*PFM)(T1,T2);
PFM pf1,pf2,...,pfm;
9
函数指针数组的每一元素可以赋值为,
ppf[0]=pf1; ppf[1]=pf2;...;ppf[m-1]=pfm;
//设 pf1,pf2,...,pfm已经合适地初始化也可以在定义的时候采用初始化语法,
PFM ppf[m]={pf1,pf2,...,pfm};
调用格式存在两种形式:
(*ppf[i])( v1,v2); ppf[k]( v1,v2);
定义一个类型属性为 type (**)(T1,T2 )二级函数指针
pfp如下:
type (**pfp)(T1,T2);
或同时初始化,type (**pfp)(T1,T2)=ppf;
10
[例 ] 返回函数指针的函数,工程文件分为两个源程序
a.cpp和 b.cpp
#include<stdio.h>
// main程序在 a.cpp源文件中
typedef void (*VFV)(void);
typedef void (*VFI)(int);
extern inline VFV GetFunct(int);
//不能写成 extern void (*)(void) GetFunct(int);
VFV pfm[ ]={GetFunct(3),GetFunct(2),GetFunct(1)};
//定义全局函数指针数组并初始化
11
void main()
{ VFV pfn=GetFunct(1);
pfn();
(*GetFunct(2))();
GetFunct(3)();
((VFI)pfm[0])(2);
(*pfm[1])();
pfm[2]();
}
//输出,
f1(); f2(); f3(); f3(); f2(); f1();
12
#include<stdio.h>
//如下程序在 b.cpp源文件中
static void f1(void) { printf("f1();\t"); }
static void f2(void) { printf("f2();\t"); }
static void f3(int) { printf("f3();\t"); }
typedef void (*VFV)(void);
extern inline VFV GetFunct(int m)
{ if (m==1) return f1
else if(m==2) return &f2;
else return (void (*)(void))&f3;
}
13
[例 ] 多路分支模拟函数菜单驱动
#include<stdio.h>
void f1(long x) { printf("f1(%d);\t",x); }
void f2(long y) { printf("f2(%d);\n",y); }
void main(void)
{ void (*ppfn[2])(long) ; ppfn[0]=&f1; ppfn[1]=&f2;
void (**pfp)(long)=ppfn; (*pfp++)(3); (**pfp)(2);
printf ("请输入一个整数,"); int k;
scanf ("%d",&k);
switch(k)
{ case 1,(*ppfn[0])(k); break;
case 2,ppfn[1](k); break;
default,break; }
}
14
[例 ] 循环实现函数的动态绑定
#include<stdio.h>
typedef void (*PPFUNC)(long);/
void f1(long x) { printf("f1(%d);\t",x); }
void f2(long y) { printf("f2(%d);\t",y); }
void main (void)
{ PPFUNC fn[ ]={&f1,f2};
int num_fn=sizeof (fn)/sizeof (fn[0]);
int k=0;
do
{ (*fn[k])(k);
printf("请输入一个整数,"); scanf("%d",&k);
}
while(0<=k && k< num_fn);
}
15
上面两个例子都采用了指向函数的指针数组,实现了一个简单的菜单模拟系统驱动程序,一个在多路分支的 switch
语句下完成实在函数的调用匹配,另一个则通过循环遍历的方式进行函数的绑定,这种函数实际地址的确定在运行时才计算出来的现象可广义地称为函数的动态绑定。
动态绑定的语法现象不是 C++所独有。
运行时的具体分支选择是编译器所无法控制的,但潜在的菜单选项则是完备地预先确定的。
16
[例 ] 函数指针的指针形参和引用形参
#include<stdio.h>
typedef void (*VFI)(int);
void f(int x) { printf ("f(%d);\t",x); }
void g(int x) { printf ("g(%d);\n",x); }
void SetFunctB (void (**ppf)(int),int m)
{ if(m==1) *ppf= f;
else *ppf= &g;}
void SetFunctA(VFI& pf,int m)
{ if(m==1) pf= f;
else pf= &g; }
void main()
{ VFI fp,gp;
SetFunctA(fp,1); (*fp)(10);
SetFunctB(&gp,2); gp(20); }
17