本文节选转载自http://blog.csdn.net/puppet_master/article/details/49368863


成员函数指针是C++中最麻烦的东东之一,准确的说是非静态成员函数指针。

静态成员函数指针

静态成员函数指针与普通函数指针一样,我们看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdafx.h"
#include <iostream>
#include <string>
#include <list>
using namespace std;

//Base类
class Base
{
public:
static void Print(int num)
{
cout<<num<<endl;
}
};

//定义一个静态成员函数指针
typedef void (*pFunc)(int);


int _tmain(int argc, _TCHAR* argv[])
{
//将静态成员函数赋给函数指针
pFunc func = Base::Print;

//通过函数指针调用函数
func(1);

system("pause");
return 0;
}

结果:

1
请按任意键继续. . .

静态成员函数与普通的函数没有太多区别,虽然他们定义在类中,但是这个成员函数不会因为对象的不同而做出不同的处理,因为它没有this指针,所以我们可以将它看成普通的函数。

非静态成员函数

但是非静态成员函指针就麻烦得多,原因非静态成员函数有一个隐藏的参数——this指针,这个东东在不同的对象中是不一样的,所以很麻烦。我们定义非静态成员函数指针的时候就需要将对象的类型也写出来。调用的时候,也要根据相应的对象来调用这个函数。看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdafx.h"
#include <iostream>
#include <string>
#include <list>
using namespace std;

//Base类
class Base
{
public:
void Print(int num)
{
cout<<num<<endl;
}
};

//定义一个成员函数指针
typedef void (Base::*pFunc)(int);


int _tmain(int argc, _TCHAR* argv[])
{
Base base;
//取成员函数的地址,必须以这种形式,不能以对象的形式获取,而且必须加上&符号
pFunc func = &Base::Print;
//调用的时候写法也比较特殊,base.*func表示函数体,是一个整体,需要用()
(base.*func)(1);

system("pause");
return 0;
}

结果:

1
请按任意键继续. . .

分析一下成员函数指针的定义和使用,我们这样定义函数指针,(Base::*pFunc)(int),其实就相当于(*pFunc)(Base*, int),相当于普通的函数指针需要多一个this指针作为参数,而这个this指针在不同的对象中一定是不同的,所以成员函数指针之间是不能互相转化的,只有同类型的对象的函数才能赋给这种对象的函数指针。

在指针赋值的时候,注意一下写法,普通的函数指针在赋值的时候,可以不写&符号,但是成员函数指针赋值的时候比较严格,如果不写的话会报出这样的错误:

error C3867: “Base::Print”: 函数调用缺少参数列表;请使用“&Base::Print”创建指向成员的指针

而且在赋值的时候,不要用对象赋值,要用 类名::函数名 这种方式赋值,使用 对象名.函数名的时候会报出这样的错误:

 error C2276: “&”: 绑定成员函数表达式上的非法操作

可见,对于成员函数指针的写法还是挺严苛的。

最后再分析一下使用,由于成员函数指针需要一个this指针作为参数,这个参数又不能直接给出,所以我们就只能通过对象来调用函数,在使用函数的时候,由于函数是一个整体,所以需要用(),在括号内部,我们通过*func获得函数,然后前面使用base.就将base作为this指针传递给了函数。