木老师教笨笨课堂——系列讲座(从函数指针到委托) 三、C++语言里的函数指针

先来回顾一下,我们说函数指针有一个重要的特性,它可以指向任何形参相同的函数。这样可以用统一的方式去调用不同的函数。(这个我还是希望笨笨同学好好思考一下,我想也是程序思想的精髓之一吧),就好比武功秘籍中九字真言一般。“统一的方式去调用不同的实现”,如果在面向对象里就是“多态”二字。

C++语言里当然也有函数指针。面向对象的引入,出现了类、对象的概念。以前函数指针只是指向的一般的函数,或者说是全局函数。但是类的出现,有了方法。于是我们会想函数指针除了指向一般的全局函数,能否指向类的方法。这是很自然的想法,就好比我们在武侠中一次掉落悬崖,没有摔死,反而获得武功秘籍一般。于是在江湖行走,看到各大悬崖,都有纵身一跳的欲望一般。

 

 

3-1

 

3-2

实践证明是

..........

..........

..........

不行的。

当然这个也很好理解,因为不是每次跳悬崖都会有武功秘籍,美女和猿猴(猿猴需要参见金庸先生的《倚天屠龙记》)的。问题出在哪儿呢?问题在于类的成员函数,类的成员函数和一般的全局函数不一样,在于它隐藏了一个this指针。比如一个类

class CA 

{

public:

       CA();

       virtual ~CA();

       void Fun(){};

};

3-1

Fun函数其实质是FunCA* this),因此我们申明一个函数指针void *fp)()指向它的话,编译是无法通过的。

有两种变通的方法,一种是把类的方法变成全局的方法,比如:

class CA 

{

public:

       CA();

       virtual ~CA();

};

void Fun(CA* pa){};

3-2

此时函数可以声明成void (*f)(CA* fa),调用如下:

f = Fun

f();

还有一种办法是把成员函数声明成静态的函数。因为静态的成员函数属于类的成员,而不再属于对象的成员,因此它的函数的形参并不带有隐含的this指针。见如下代码:

class CA 

{

public:

    CA();

    virtual ~CA();

    void Fun(){printf("CA::Fun()"n");};

    static void StaticFun() {printf("CA::StaticFun()"n");}

};

此时函数声明为:void (*f3)();

 

f3 = CA::StaticFun;

f3();

 

那如果不想变通怎么办呢?当然也不是没有办法滴!只不过函数指针声明和调用的方法都有所不同。这个地方 笨笨同学注意了!因为一般的书很少会涉及到这个问题。

类成员的函数指针声明:

1、比如表示CA类的Fun()方法的函数指针,声明如下

void (CA::*f1)();

2、将函数指针指向该方法成员

f1 = CA::Fun;

类成员的函数指针调用

一般我们很容易写成 f1(); 但这种在编译的时候,编译器会报错“term does not evaluate to a function

仍然是因为这样的调用,函数指针无法获得this指针的原因。应该写成:

CA a;

(a.*f1)();

 

笨笨看到此处,说:“这有什么用呢?太复杂了,我不学了。”

其实木老师讲了这么多,也没有打算让笨笨学会,因为笨笨实在是..........太笨了。笨笨这个角色的引入主要还是为了广大的聪明读者。一边去,笨笨。(嘘!不过不能让他知道,因为即使他再笨,也知道“一边去”并不是什么好话)。

..........实际上这样的函数指针的用法是会在面向对象的语言里用的,一个最典型的就是MFC里的消息函数。大家如果有兴趣,先利用VC的搜索工具,搜索“::*”可以发现总共有246条记录。其中pfn_这样的前缀的都是消息函数指针。如果想仔细探究,就等木老师以后讲解MFC里的消息机制,当然大名鼎鼎的《深入浅出MFC》或者《深入解析MFC》两本书都可以看,但是木老师的建议是最好看看书,然后直接看MFC的源码,调试MFC的源码会比较好一点。

函数指针到此,应该说介绍得较为全面了。当然还有一个就是函数指针数组,我们并没有介绍,它和一般的数组区别并不大,只不过数组里存储的是函数指针而已。我们说函数指针有一个重要的特性,即函数指针可以指向任何形参相同的函数,有了这个特性,则可以用统一的调用方式来完成不同的实现。我们知道在面向对象的概念中,多态是一个非常重要的概念,在面向对象的语言里,我们是使用虚函数或者纯虚函数来实现多态这个概念,那么在面向过程的C语言里,则是用函数指针来完成这一概念。下一节里,我们就来介绍C#里的委托机制。

posted @ 2008-12-02 14:45  helloj2ee  阅读(312)  评论(0编辑  收藏  举报