指向函数的指针

(一) 用函数指针变量调用函数

  可以用指针变量指向整形变量、字符串、数组、结构体、也可以指向一个函数。一个函数在编译时被分配一个入口地址。这个入口地址就称为函数指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。用简单的数值比较为例:

复制代码
1 #include <stdio.h>
2 #include <stdlib.h>
3
4  int main()
5 {
6 int max(int,int);
7 int (*p)(int,int);
8 int a,b,c;
9 p = max;
10 scanf("%d,%d",&a,&b);
11 c = (*p)(a,b);
12 printf("a=%d,b=%d,max=%d\n",a,b,c);
13 return 0;
14 }
15
16 int max(int x,int y)
17 {
18 int z;
19 if(x>y) z = x;
20 else z = y;
21 return(z);
22 }
复制代码

  main函数中的" c = max(a,b); " 包括了一次函数的调用。每一个函数都占用一段内存单元。因此,可以用一个指针变量指向一个函数,通过指针变量来访问它指向的函数。

  第7行:int (*p)( int,int );  用来定义 p 是一个指向函数的指针变量,该函数有两个整形参数,函数值为整形。注意 *p 两侧的括号不可省略,表示 p 先与 * 结合,是指针变量,然后再与后面的 ( ) 结合,表示此指针变量指向函数,这个函数值 (即函数的返回值) 是整形的。如果写成 int *p ( int,int ) ,由于( )的优先级高于 *,它就成了声明一个函数P( 这个函数的返回值是指向整形变量的指针)。

  赋值语句 p = max ; 作用是将函数 max 的入口地址赋给指针变量p。和数组名代表数组首元素地址类似,函数名代表该函数的入口地址。这时 p 就是指向函数 max 的指针变量,此时 p 和 max都指向函数开头,调用 *p 就是调用 max 函数。但是p作为指向函数的指针变量,它只能指向函数入口处而不可能指向函数中间的某一处指令处,因此不能用 *(p + 1)来表示指向下一条指令。

  注意:

  (1) 指向函数的指针变量的一般定义形式为:

  数据类型 (*指针变量名)(函数参数列表)

  这里数据类型就是函数返回值的类型

  (2) int (* p) ( int,int ); 它只是定义一个指向函数的指针变量 p, 它不是固定指向哪一个函数的,而只是表示定义这样一个类型的变量,它是专门用来存放函数的入口地址的。在程序中把哪一函数(该函数的值应该是整形的,且有两个整形参数)的地址赋给它,他就指向哪一个函数。在一个函数中,一个函数指针变量可以先后指向同类型的不同函数。

  (3) p = max; 在给函数指针变量赋值时,只需给出函数名而不必给出函数参数,因为是将函数的入口地址赋给 p ,而不涉及 实参和形参的结合问题,不能写成 p = max(a,b);

  (4) c = (*p)(a,b) 在函数调用时,只需将( *p ) 代替函数名即可,后面实参依旧。

  (5) 对于指向函数的指针变量,像 p++ ,p+n.....是无意义的。

  (二) 用指向函数的指针作为函数参数

  函数指针变量通常的用途之一就是把指针作为参数传递到其他函数。

  函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量,也可以是指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。

  void  sub ( int ( *x1) (int), int (*x2) (int,int) )

    {

      int a,b,i,j;

      a = (*x1)(i);      /* 调用 f1 函数 */

      b = (*x2)(i)(j);    /* 调用 f2 函数 */

    }

  如果实参为两个 函数名 f1 和 f2. 在函数首部定义x1、x2为函数指针变量,x1指向的函数有一个整形形参,x2指向的函数有两个形参。i 和 j 是函数f1 和 f2所要的参数。函数sub的形参 x1、x2(指针变量)在函数 sub 未被调用时并不占用内存单元,也不指向任何函数。在sub被调用时,把实参函数 f1 和 f2的入口地址传给形式指针变量 x1 和 x2.

  既然在 sub 函数中要调用 f1 和 f2 函数,为什么不直接调用f1 和 f2而要用函数指针变量呢? 确实,如果只是用到f1 和 f2 函数,完全可以在sub函数中直接调用f1 和 f2,而不必设指针变量 x1 和 x2。 但是,如果在每次调用sub时,调用的函数不是固定的,下次是f3 和 f4,再是f5 和 f6...这时用指针变量就比较方便了。

我们在类里面会定义成员函数,同时我们也希望定义成员函数指针。因此需要解决3个问题,第一怎么定义类的函数指针,第二赋值,第三使用。
我定义一个类,

class A
{
public:
    
int add(int,int);
    
int mul(int,int);
    
int div(int,int);
};

int A::add(int a,int b)
{
    
return a + b;
}

int A::mul(int a,int b)
{
    
return a * b;
}

int A::div(int a,int b)
{
    
return (b !=0 ? a/b : a);
}

我现在想要定义一个指针,指向A类型中返回值为int,参数为两个int的函数指针。熟悉C的同学马上会写出typedef int (*oper)(int,int)。但是这个用到C++里就有问题了,
因为我们知道,类的非static成员方法实际上还有this指针的参数。比如add方法,它实际的定义可能会这样int add(A* this,int a,int b);因此,我们不能简单把C语言里的那套东西搬过来,我们需要重新定义这种类型的指针。正确做法是加上类型,typedef int (A::*Action)(int,int)

typedef int (A::* Action)(int,int);

int main()
{
    A a;
    Action p 
= &A::add;
    cout 
<< (a.*p)(1,2<< endl;
    
return 0;
}

 

Action p = &A::add;这个就是赋值语句
调用的时候注意,直接这样(*p)(1,2)是不行的,它必须绑定到一个对象上
(a.*p)(1,2);我们也可以把类的函数指针定义在类的声明里。
class A
{
public:
    
int add(int,int);
    
int mul(int,int);
    
int div(int,int);

    
int (A::*oper)(int,int);
};

上面这种方式是针对非static成员函数的,那么static成员函数的函数指针应该怎么定义呢,还能用上面这种方式吗?我们知道static成员函数是没有this指针的,所以不会加上的类的限定,它的函数指针定义方式和C里面的函数指针定义方式一样的。

class A
{
public:
    
int add(int,int);
    
int mul(int,int);
    
int div(int,int);

    
static int sub(int,int);
};

int A::sub(int a,int b)
{
    
return a - b;
}

int main()
{
    
int (*pp)(int,int= &A::sub;
    cout 
<< (*pp)(10,5<< endl;
    
    
return 0;
}

总结起来,非static成员函数的函数指针需要加上类名,而static的成员函数的函数指针和普通的函数指针一样,没有什么区别。
另外注意一点的是
如果函数指针定义在类中,调用的时候有点区别。

class A
{
public:

    
int add(int,int);
    
int mul(int,int);
    
int div(int,int);

    
int (A::*pfunc)(int,int);
};

int main()
{
    A a;
    a.pfunc 
= &A::add;
    cout 
<< (a.*(a.pfunc))(1,2<< endl;
    
return 0;
}

 

posted on 2012-08-15 15:42 章涛 阅读(362) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2012年8月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜