类的普通成员函数的指针

来源:互联网 发布:伦敦政经知乎 编辑:程序博客网 时间:2024/04/27 08:06
很多朋友都知道虚函数有虚函数指针,并且存放在对象的虚函数表中,它和普通成员变量一样与对象相关,因此虚函数的指针是和对象级的。一个类的普通成员函数是类级的,因此普通成员函数的指针也是类级的。一个类的普通成员函数的指针,少有文献提及,因为很少需要用到普通成员函数的指针。尽管如此,在一些特殊的场合,还是有可能需要用到的。

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, pmf)(3);
         pcallmemfun(bFoo, pmf)(4);

         ((aFoo).*(aFoo.pmf))(3);
         return 0;
}
0 0