指向成员函数的指针

取一个非静态成员函数的地址,如果该函数是nonvirtual,则得到的结果是它在内存中真正的地址。然而这个值也不是完全的,它也需要被绑定于某个class object的地址上,才能够通过它调用该函数。所有的非静态成员函数都需要对象的地址(以参数this指出)

一个指向成员函数的指针,其声明语法如下所示:

double //return type

(Point::* //class the function is member

pmf) // name of pointer to member

(); // argument list

然后我们可以这样定义并初始化该指针:

double (Point::*coord)() = &Point::x;

也可以这样指定其值:

coord = &Point::y;

想调用它,可以这样做:

(origin.*coord)(); (ptr->*coord)();

指向member function的指针的声明语法,以及指向“member selection运算符”的指针,其作用是作为this指针的空间保留者。这也就是为什么static member functions(没有this指针)的类型为“函数指针”,而不是“指向member function之指针”的原因。使用一个成员函数的指针,如果并不用于虚函数、多重继承、虚基类等情况的话,并不会比使用一个“nonmember function 指针”的成本更高。

支持“指向virtual member functions”的指针

注意下面的程序片段:

float (Point::*pmf)() = &Point::z;

Point *ptr = new Point3d;

pmf,一个指向成员函数的指针,被设置为Point::z()(一个虚函数)的地址。如果我们直接经由ptr调用z():

ptr->z();

则被调用的是Point3d::z()。但如果我们从pmf间接调用z()呢?

(ptr->*pmf)();

仍然是Point::z()被调用吗?也就是说,虚拟机制仍然能够在使用“指向成员函数的指针”的情况下正常运行吗?如何实现的呢?

面对一个虚函数,其地址在编译时期是未知的,所能知道的仅仅是虚函数在其相关的虚表中的索引值。也就是说,对一个虚成员函数取其地址,所能获得的只是一个索引值。假设我们有以下的Point声明:

Class Point{

public:

virtual ~Point();

float x();

float y();

virtual float z();

//…

}

然后取destructor的地址:

&Point::~Point;

得到的结果是1。取x()y()的地址:

&Point::x();

&Point::y();

得到的是函数在内存中的地址,因为它们不是virtual。取z()的地址:

&Point::z();

得到的结果是2,通过pmf来调用z(),会被内部转化为一个编译时期的式子,一般形式如下:

( *ptr->vptr[(int)pmf] )( ptr );

对一个指向成员函数的指针评估求值,会因为该值有两种意义而复杂化,其调用操作也将有别于常规调用操作。pmf的内部定义,也就是:

float (Point::*pmf)();

必须允许该函数能够寻址出nonvirtual x()virtual z()两个成员函数,这两个成员函数有着相同的原型,只不过其中一个代表内存地址,另外一个代表在对应虚表中的索引值。因此,编译器必须定义pmf使它能够(1)含有两种数值,(2)更重要的是其数值可以被区别代表内存地址还是虚表中的索引值。

cfront2.0的非正式版本中,这两个值被内含在一个普通的指针内。它使用如下技巧:

(((int)pmf) & ~127)

? (*pmf)(ptr) //non-virtual invocation

: ( *ptr->vptr[(int)pmf] )( ptr ); //virtual invocation

这种实现技巧必须假设继承体系中最多只能够有128个虚函数。这并不是我们所希望的,但却证明是可行的。

在多重继承之下,指向Member Functions的指针

《深入理解C++对象模型》P178~180

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wuliming_sc/archive/2009/01/31/3855694.aspx

你可能感兴趣的:(指向成员函数的指针)