170 likes | 362 Views
第 9 章 函数指针. 四、 typedef 关键字、函数指针与重载函数 五、函数指针构成的数组. 四、 typedef 关键字、函数指针与重载函数 左边声明函数指针别名 VFI ,PFD ,右边定义函数指针 vfi,pfd 。 typedef void (*VFI)(int); void (*vfi)(int); typedef double* (*PFD) (double* ,double*); double* (*pfd)(double* ,double*);
E N D
第9章 函数指针 • 四、typedef关键字、函数指针与重载函数 • 五、函数指针构成的数组
四、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关键字得到函数指针定义语句。
函数指针的类型别名在返回函数指针的函数上有独到之函数指针的类型别名在返回函数指针的函数上有独到之 • 处。可用函数指针的类型别名定义函数指针。例如: • PFD pf, pfd,pmax; VFI vfi,pvfi; • 重载函数通过函数名与形参类型列表被编译器细分为不 • 同的函数,重载函数的入口地址是唯一的,可以定义指向重 • 载函数某个版本的函数指针。 • 根据函数指针的类型属性与其所指向的函数名的类 型 • 属性进行匹配。
[例]函数指针与重载函数,函数指针根据重载函数名的[例]函数指针与重载函数,函数指针根据重载函数名的 • 入口类型匹配 • #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;
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));}
//输出: &&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消息映射中多次采用。
一般地,设源函数指针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) 的地址并类型转换
五、函数指针构成的数组 • 数组是同类型元素构成的数据集合,如果这些元素恰好 • 是函数指针,则形成函数指针数组,其定义格式为: • 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;
函数指针数组的每一元素可以赋值为: • 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;
[例]返回函数指针的函数,工程文件分为两个源程序 • 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)}; • //定义全局函数指针数组并初始化
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();
#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; • }
[例]多路分支模拟函数菜单驱动 • #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; } • }
[例]循环实现函数的动态绑定 • #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); • }
上面两个例子都采用了指向函数的指针数组,实现了一上面两个例子都采用了指向函数的指针数组,实现了一 • 个简单的菜单模拟系统驱动程序,一个在多路分支的switch • 语句下完成实在函数的调用匹配,另一个则通过循环遍历的 • 方式进行函数的绑定,这种函数实际地址的确定在运行时才 • 计算出来的现象可广义地称为函数的动态绑定。 • 动态绑定的语法现象不是C++所独有。 • 运行时的具体分支选择是编译器所无法控制的,但潜在 • 的菜单选项则是完备地预先确定的。
[例]函数指针的指针形参和引用形参 • #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); }
请打开“第 9 章(2).ppt” 请打开“第11章.ppt”