好记性不如铅笔头

C && C++, 编程

【转】函数指针

转自【 http://hipercomer.blog.51cto.com/4415661/792300 】,有删改

======================

CONTENTS

2 函数指针简单介绍

2.1 什么是函数指针

函数指针是一个指向函数的指针,函数指针表示一个函数的入口地址。使用函数指针的好处就是在处理“在运行时根据数据的具体状态来选择相应的处理方式”这种需求时更加灵活。
简单的例子:

float minus(float a,float b){return a-b;} 
typedef float (*pf)(float,float); 
。。。。。
。。。。。
void switch_fp_impl(float a,float b,pf p) 
{ 
      float result=0.0; 
      result=p(a,b); 
} 
int main()
{
      int i=0;
      for(i=0;i<N;i++)
      {
             switch_fp_impl(12.32,54.14,minus);
      }
      return 0; 
}

3 C/C++函数指针的语法

从语法上讲,有两种不兼容的函数指针形式:
(1)    指向C语言函数和C++静态成员函数的函数指针
(2)    指向C++非静态成员函数的函数指针
不兼容的原因是因为在使用C++非静态成员函数的函数指针时,需要一个指向类的实例的this指针,而前一类不需要。

3.1 定义一个函数指针

指针是变量,所以函数指针也是变量,因此可以使用变量定义的方式来定义函数指针,对于普通的指针,可以这么定义:
int a=10;
int *pa=&a;
这里,pa是一个指向整型的指针,定义这个指针的形式为:
int * pa;
区别于定义非指针的普通变量的“形式”就是在类型中间和指针名称中间加了一个“*”,所以能够表达不同的“内容”。这种形式对于表达的内容是完备的,因为它说明了两点:(1)这是一个指针(2)这是一个指向整型变量的指针
以下给出三个函数指针定义的形式,第一个是C语言的函数指针,第二个和第三个是C++的函数指针的定义形式(都是指向非静态函数成员的函数指针):
int (*pFunction)(float,char,char)=NULL;
int (MyClass::*pMemberFunction)(float,char,char)=NULL;
int (MyClass::*pConstMemberFunction)(float,char,char) const=NULL;

3.3 给函数指针赋值和调用

给函数指针赋值,就是为函数指针指定一个函数名称。这个过程很简单,下面是两个例子:
int func1(float f,int a,int b){return f*a/b;}
int func2(float f,int a,int b){return f*a*b}
然后我们给函数指针pFunction赋值:
pFunction=func1;
pFunction=&func2;
上面这段代码说明了两个问题:(1)一个函数指针可以多次赋值(想想C++中的引用)(2)取地址符号是可选的,却是推荐使用的。

最后我们来使用这个函数:
pFunction(10.0,’a’,’b’);
(*pFunction)(10.0,’a’,’b’);

在C++中,对于赋值,你必须要加“&”,而且你还必须再次之前已经定义好了一个类实例,取地址符号要操作于这个类实例的对应的函数成员上。在使用成员函数的指针调用成员函数时,你必须要加类实例的名称,然后再使用.*或者->*来使用成员函数指针。举例如下:

MyClass
{
public:
      int func1(float f,char a,char b)
      {
          return f*a*b;
      }
      int func2(float f,char a,char b) const
      {
	return f*a/b;
      }
}

首先来赋值:
MyClass mc;
pMemberFunction= &mc.func1;  //必须要加取地址符号
pConstMemberFunction = &mc.func2;
接下来,调用函数:
(mc.*pMemberFunction)(10.0,’a’,’b’);
(mc.*pConstMemberFunction)(10.0,’a’,’b’);
例子:

#include<stdio.h> 
float func1(float f,char a,char b) 
{ 
      printf("func1\n"); 
      return f*a/b; 
}  
float  func2(float f,char a,char b) 
{ 
      printf("func2\n"); 
      return f*a*b; 
} 

class MyClass 
{ 
public:  
      MyClass(float f)  
      {  
             factor=f;  
      }  
      float func1(float f,char a,char b)  
      {  
             printf("MyClass::func1\n"); 
             return f*a/b*factor;      
      } 
      float func2(float f,char a,char b) const 
      { 
             printf("MyClass::func2\n"); 
             return f*a*b*factor; 
      } 
private:  
      float factor;  
}; 
 
int main(int argc,char *argv[]) 
{ 
       float (*pFunction)(float,char,char)=NULL; 
      float (MyClass::*pMemberFunction)(float,char,char)=NULL;  
      float (MyClass::*pConstMemberFunction)(float,char,char)const=NULL; 

      float f=10.0;  
      char a='a',b='b';  
      float result;  
      pFunction=func1;  
      printf("pointer pFunction's address is:%x\n",pFunction);  
      result=(*pFunction)(f,a,b); 
        printf("result=%f\n",result); 
  
      pFunction=&func2; 
 
      printf("pointer pFunction's address is:%x\n",pFunction);  
      result=pFunction(f,a,b);  
        printf("result=%f\n",result);  
      if(func1!=pFunction)  
             printf("not equal.\n"); 
       
      pMemberFunction=&MyClass::func1;  
      MyClass mc1(0.2);  
      printf("pointer pMemberFunction's address is:%x\n",pMemberFunction);  
      result=(mc1.*pMemberFunction)(f,a,b);  
      printf("result=%f\n",result); 
 
      pConstMemberFunction=&MyClass::func2;  
      MyClass mc2(2);  
      printf("pointer pConstMemberFunction's address is:%x\n",pConstMemberFunction);  
      result=(mc2.*pConstMemberFunction)(f,a,b);  
      printf("result=%f\n",result); 

      return 0; 
} 

使用类的静态函数成员的函数指针和使用C语言的函数很类似,这里仅仅给出一个例子和其执行结果:
程序代码为: 

#include<iostream> 
class MyClass 
{ 
public: 
      static float plus(float a,float b) 
      { 
             return a+b; 
      }     
}; 
 
int main() 
{ 
      float result,a=10.0,b=10.0;  
      float (*p)(float,float);  
      p=&MyClass::plus;  
      result=p(a,b);  
      printf("result=%f\n",result);  
      return 0; 
}

3.4 函数指针作为参数

例子:

#include<stdio.h> 
float add(float a,float b){return a+b;}  
float minus(float a,float b){return a-b;}
int pass_func_pointer(float (*pFunction)(float a,float b)) 
{ 
      float result=pFunction(10.0,12.0); 
      printf("result=%f\n",result); 
} 
int main()
{ 
      pass_func_pointer(add); 
      pass_func_pointer(minus); 
      return 0; 
}

3.5 使用函数指针作为返回值

所以对于以下形式:
float (* func(char op) ) (float ,float)
其具体含义就是,声明了这样一个函数:
l  其名称为func,其参数的个数为1个;
l  其各个参数的类型为:op—char;
l  其返回变量(函数指针)类型为:float(*)(float,float)
再次强调:函数指针时变量哦。
到了这里之后,我们再来分析一下unix的系统调用函数signal的定义形式:
void (*signal)(int signo,void (*func)(int)))(int);
其具体含义为就是,声明了这样一个函数:
l  其函数名称为:signal
l  其参数个数为:2
l  其各个参数的类型为:signo–int, func— void (*)(int)
l  其返回的变量(函数指针)的类型为:void(*)(int)
上面这个函数比较经典,有一个参数类型为函数指针,返回值还是函数指针。

例子:

float add(float a,float b){return a+b;} 
float minus(float a,float b){return a-b;}
float(* FunctionMap(char op) )(float,float) 
{
      switch(op) 
      { 
             case '+': 
                    return add; 
                    break;  
             case '-': 
                    return minus; 
                    break; 
             default: 
                    exit(1); 
      } 
} 
int main() 
{ 
      float a=10,b=5; 
      char ops[]={'+','-'}; 
      int len=strlen(ops);  
      int i=0; 
      float (*returned_function_pointer)(float,float); 
      for(i=0;i<len;i++) 
      { 
             returned_function_pointer=FunctionMap(ops[i]); 
             printf("%c %f\n",ops[i],returned_function_pointer(a,b)); 
      } 
      return 0; 
} 

3.6 使用函数指针数组

现在我们来类比函数指针数组的定义,定义一个指向函数指针类型为:float (*)(float,float)的函数指针数组,数组长度为10.正确的形式为:
float(* pFunctionArray[10])(float,float)
下面是一个例子程序:

float add(float a,float b){return a+b;} 
float minus(float a,float b){return a-b;} 
float multiply(float a,float b){return a*b;} 
float divide(float a,float b){return a/b;} 
int main() 
{ 
      float(*func_pointers[4])(float,float)={add,minus,multiply,divide}; 
      int i=0;  
      float a=10.0,b=5.0;  
      for(i=0;i<4;i++)  
      {  
             printf("result is %f\n",func_pointers[i](a,b));  
      }  
      return 0; 
}

3.7 使用typedef

现在我们要将float (*)(float,float)类型声明为一种新类型:
typedef float(*fpType)(float,float);
这样我们就可以用fpType来表示float (*)(float,float)这种类型了。所以定义一个新的指向float (*)(float,float)类型的指针变量的时候,我们就可以采用下面这种形式了:
fpType pFunction;
在定义函数指针数组的时候可以这样定义:
fpType pFunctions[10];
在定义函数指针类型参数时可以这样定义:
void func(fpType pFunction);
在定义函数指针类型的返回值时可以这样定义:
fpType func(int a);
现在我们再来看一下,unix中的那个signal函数,其形式为:
void (*signal)(int signo,void (*func)(int)))(int);
现在我们定义一个类型为:
typedef void (*pSgnType)(int);
这样上面的函数就能表达为:
pSgnType signal(int signo,pSgnType func);
这样是不是看起来清爽多了。
其实上面的signal函数也能这样定义:
首先引入新类型:
typedef void SgnType(int)
然后signal函数的声明改为:
SgnType *signal(int signo,SgnType *func);

发表评论

19 − 7 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据