原文出处:点击打开链接
在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()
通过上面的代码可以发现,类成员函数指针同样可以实现多态!