很 多朋友都知道虚函数有虚函数指针,并且存放在对象的虚函数表中,它和普通成员变量一样与对象相关,因此虚函数的指针是和对象级的。一个类的普通成员函数是 类级的,因此普通成员函数的指针也是类级的。一个类的普通成员函数的指针,少有文献提及,因为很少需要用到普通成员函数的指针。尽管如此,在一些特殊的场 合,还是有可能需要用到的。
1) 成员函数简介
在 C++ 中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址 , 在需要的时候可以任意转换并直接调用。但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。 C++ 专门为成员指针准备了三个运算符 : "::*" 用于指针的声明,而 "->*" 和 ".*" 用来调用指针指向的函数。比如 :
#include <iostream>
using namespace std;
class Foo
{
public:
double virtual One( long inVal );
double virtual Two( long inVal );
};
double Foo::One(long inVal)
{
return inVal;
}
double Foo::Two(long inVal)
{
return inVal;
}
// 定义一个指向成员函数的指针类型,这些成员函数的返回值类型应该是 double ,并且有一个 long 类型的参数。
typedef double (Foo::*PMF)(long);
// 定义一个以对象调用函数指针的方法,其中: obj :调用成员函数指针的对象; pointer :成员函数的指针。
// 注意:因为 ".*" 优先级较低,所以该符号的两端,均需加上括号
#define callmemfun(obj, pointer) ((obj).*(pointer))
// 定义一个以对象指针调用函数指针的方法,其中: pobj :调用成员函数指针的对象指针; pointer :成员函数的指针。
// 注意:因为 "->*" 优先级较低,所以该符号的两端,均需加上括号
#define pcallmemfun(pobj, pointer) ((pobj)->*(pointer))
int main(void)
{
Foo aFoo;
// 注意:获取一个成员函数指针的语法要求很严格
// 1. 不能使用括号,比如 PMF pmf = &(Foo::Two) 是错误的
// 2. 必须有类限定符,如 PMF pmf = &Two 是错误的, 即使是在类定义的内部也须加上类限定符, 即 PMF pmf = &Foot::Two
// 3. 必须使用取址符号:比如 PMF pmf = Foo::Two 是错误的,虽然普通函数指针可以这样 ( 其实对以成员函数指针,某些编
// 译器也是允许这样,但最好还是加上取址符号 ) ,应该写成 PMF pmf = &Foot::Two
PMF pmf = &Foo::Two; // 取成员函数指针
double result = callmemfun(aFoo, pmf)(2);
cout << result << endl;
result = pcallmemfun(&aFoo, pmf)(3);
cout << result << endl;
return 0;
}
无 法将成员函数类型转换为其它任何稍有不同的类型,简单的说,每个成员函数指针都是一个独有的类型,无法转换到任何其它类型。即使两个类的定义完全相同也不 能在其对应成员函数指针之间做转换。这有点类似于结构体的类型,每个结构体都是唯一的类型,但不同的是,结构体指针的类型是可以强制转换的。有了这些特殊 的用法和严格的限制之后,类成员函数的指针实际上是变得没什么用了。这就是我们平常基本看不到代码里有 "::*", ".*" 和 "->*" 的原因。
2) 使用成员函数指针访问类的私有成员函数
#include <iostream>
using namespace std;
class Foo;
typedef double (Foo::*PMF)(long);
#define callmemfun(obj, pointer) ((obj).*(obj.pointer))
#define pcallmemfun(pobj, pointer) ((pobj)->*(pobj->pointer))
class Foo
{
public:
PMF pmf;
Foo()
{
pmf = &Foo::Three; // 取得私有成员函数的指针
}
public:
inline double One(long inVal)
{
return inVal;
}
inline double Two(long inVal)
{
return 2 * inVal;
}
private:
inline double Three(long inVal)
{
cout << "this is in Three..." << endl;
return 3 * inVal;
}
};
int main(void)
{
Foo aFoo;
Foo* bFoo = new Foo;
// 通过公有成员变量 pmf ,很轻松地调用了私有成员函数 Three
callmemfun(aFoo, aFoo.pmf)(3);
pcallmemfun(bFoo, bFoo->pmf)(4);
((aFoo).*(aFoo.pmf))(3);
return 0;
}