85
技術社區[雲棲]
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