原文出处:点击打开链接
在C++中类成员函数指针是一种比较特别的指针,尽管直接使用类成员函数的情况不太多,但是还是有必要详解一下这类指针。
具体语法
首先说明一下类成员函数指针的声明方式:
Return_Type (Class_Name::* pointer_name) (Argument_List); Return_Type: member function return type. Class_Name: name of the class in which the member function is declared. Argument_List: member function argument list. pointer_name: a name we'd like to call the pointer variable.通过函数指针调用类成员函数需要使用操作符.*或者->*,具体使用参考下面这段代码:
#include <iostream> #include <string> using std::string; class Foo{ public: int f(string str){ std::cout<<"Foo::f()"<<std::endl; return 1; } }; int main(int argc, char* argv[]){ int (Foo::*fptr) (string) = &Foo::f; Foo obj; (obj.*fptr)("str");//call: Foo::f() through an object Foo* p=&obj; (p->*fptr)("str");//call: Foo::f() through a pointer }
类成员函数指针不是一般的指针
通常的函数指针指向的地址都是一个准确的代码入口地址,但是不难想象类成员函数指针指向的应该是一个相对的位置(相对于整个类的偏移地址)。这一点很好证明。
类中的静态函数实际和全局函数一样,有着确定的入口地址,类成员静态函数没有this指针,但是却可以共享整个类的命名范围,也可以访问到类中的其他成员。现在来看下面这段代码:
#include <iostream> #include <string> using std::string; class Foo{ public: static int f(string str){ std::cout<<"Foo::f()"<<std::endl; return 1; } }; int main(int argc, char* argv[]){ //<pre name="code" class="cpp">int (Foo::*fptr) (string) = &Foo::f;//error
int (*fptr) (string) = &Foo::f;//correct (*fptr)("str");//call Foo::f()} 其中
int (Foo::*fptr) (string) = &Foo::f;//error会引起如下错误:
cannot convert 'int (*)(std::string)' to 'int (Foo::*)(std::string)
这说明了类成员函数指针不是一般的函数指针
类成员函数指针的转换
还是先来看看下面的代码:
#include <iostream> class Foo{ public: int f(char* c=0){ std::cout<<"Foo::f()"<<std::endl; return 1; } }; class Bar{ public: void b(int i=0){ std::cout<<"Bar::b()"<<std::endl; } }; class FooDerived:public Foo{ public: int f(char* c=0){ std::cout<<"FooDerived::f()"<<std::endl; return 1; } }; int main(int argc, char* argv[]){ typedef int (Foo::*FPTR) (char*); typedef void (Bar::*BPTR) (int); typedef int (FooDerived::*FDPTR) (char*); FPTR fptr = &Foo::f; BPTR bptr = &Bar::b; FDPTR fdptr = &FooDerived::f; //bptr = static_cast<void (Bar::*) (int)> (fptr); //error fdptr = static_cast<int (Foo::*) (char*)> (fptr); //OK: contravariance Bar obj; ( obj.*(BPTR) fptr )(1);//call: Foo::f() } Output: Foo::f()
语句:
bptr = static_cast<void (Bar::*) (int)> (fptr);无法正常执行,因为非静态、非虚的类成员函数指针都是属于强类型,所以无法进行转换。
但是语句
fdptr = static_cast<int (Foo::*) (char*)> (fptr);可以执行,这是因为两者所属的类存在继承关系。
Bar obj; <p> ( obj.*(BPTR) fptr )(1);//call: Foo::f()可以执行,因为fptr是静态绑定的</p>
虚成员函数指针
#include <iostream> class Foo{ public: virtual int f(char* c=0){ std::cout<<"Foo::f()"<<std::endl; return 1; } }; class Bar{ public: virtual void b(int i=0){ std::cout<<"Bar::b()"<<std::endl; } }; class FooDerived:public Foo{ public: int f(char* c=0){ std::cout<<"FooDerived::f()"<<std::endl; return 1; } }; int main(int argc, char* argv[]){ typedef int (Foo::*FPTR) (char*); typedef void (Bar::*BPTR) (int); FPTR fptr=&Foo::f; BPTR bptr=&Bar::b; FooDerived objDer; (objDer.*fptr)(0);//call: FooDerived::f(), not Foo::f() Bar obj; ( obj.*(BPTR) fptr )(1);//call: Bar::b() , not Foo::f() } Output: FooDerived::f() Bar::b()
通过上面的代码可以发现,类成员函数指针同样可以实现多态!