C++中類成員函數指針詳解
原文出處:點擊打開鏈接
在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" >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()
通過上麵的代碼可以發現,類成員函數指針同樣可以實現多態!
最後更新:2017-04-03 05:39:09