C++指向类成员的指针的使用(详细介绍)

1、首先普通函数指针不能被赋值为成员函数的地址,即使返回类型和参数完全匹配。例如:下面是的pfi是一个普通函数指针,它没有参数,返回类型为int
int (*pfi)();
若有两个全局函数,HeightIs()WidthIs():
int HeightIs();
int WidthIs();
则下面的的赋值操作是合法的:
pfi = HeightIs();
pfi = WidthIs();

但如今有一个类Screen也定义了两个访问函数-height()width(),它们也没有参数,
返回类型也为int
inline int Screen::height() { return _height; }
inline int Screan::width()  { return _width;  }
但是下面的赋值是非法的,会导致编译错误产生。
pfi = &Screen::height();

为什么会出现违例?因为,成员函数有一个非成员函数不具有的属性-它的类(class)
指向成员函数的指针必须于其赋值的函数类型匹配,不是两个方面而是三个方面:
(1)参数类型和个数(2)返回类型 (3) 它所属的类类型。

成员函数指针和普通函数指针之间的不匹配是由于这两种指针在表示上的区别。函数指针
存储函数的地址,可以被用来直接调用那个函数。成员函数指针首
先必须被绑定在一个对象或者一个指针上,才能得到被调用对象的this 指针,然后才调
用指针所指的成员函数。在下面将看到成员函数指针怎样被绑定到一个对象或指针上,
以便调用一个成员函数。


2、成员函数指针的声明:
拿下面这个类来说明:
class Screen {
public:
// 成员函数
void home() { _cursor = 0; }
void move( int, int );
char get() { return _screen[_cursor]; }
char get( int, int );
bool checkRange( int, int );
int height() { return _height; }
int width() { return _width; }
//....
public://修正
string _screen;
string::size_type _cursor;
short _height;
short _width;
};

成员函数指针的声明要求扩展的语法,它要考虑类的类型。对指向类数据成员的指针也
是这样。考虑Screen 类的成员_height 的类型。它的完整类型是short 型的Screen 类的成
指向_height 的指针的完整类型是指向short 型的Screen 类的成员的指针这可以
写为:
short Screen:*
指向short型的Screen类的成员的指针定义如下:
short Screen::* ps_Screen;
ps_Screen 可以用_height 的地址初始化如下
short Screen::*ps_Screen = &Screen::_height;

在数据成员指针和普通指针之间的不匹配也是由于这两种指针的表示上的区别。普通指
针含有引用一个对象所需的全部信息。数据成员指针在被用来访问数据成员之前,必须先被
绑定到一个对象或指针上。

定义一个成员函数指针需要指定函数返回类型,参数表和类。例如指向Screen 成员函
数并且能够引用成员函数height()width()的指针类型如下:
int (Screen::*) ();
这种类型指定了一个指向类Screen的成员函数的指针,它没有参数,返回值类型为int
指向成员函数的指针可被声明,初始化及赋值如下
// 所有指向类成员的指针都可以用0 赋值
int (Screen::*pmf1)() = 0;
int (Screen::*pmf2)() = &Screen::height;
pmf1 = pmf2;
pmf2 = &Screen::width;
也可以用typedef 定义,这样语法更容易读。如:
typedef Screen& (Screen::*Action)();
Action default = &Screen::home;
Action next = &Screen::forward;


3、怎样使用指向类成员的指针
   类成员的指针必须总是通过特定的对象或指向改类型的对象的指针来访问。是通过
使用两个指向成员操作符的指针(针对类对象和引用的.* ,以及针对指向类对象的指针的->*)
(操作符.*->*的说明如下:
pm-expression :
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression

The binary operator .* combines its first operand, which must be an object of class type,
with its second operand, which must be a pointer-to-member type.

The binary operator ->* combines its first operand, which must be a pointer to an object
of class type, with its second operand, which must be a pointer-to-member type.

In an expression containing the .* operator, the first operand must be of the class type
of the pointer to member specified in the second operand or of a type unambiguously derived
from that class.

In an expression containing the ->* operator, the first operand must be of the type "pointer
to the class type" of the type specified in the second operand, or it must be of a type
unambiguously derived from that class.

)

如下面例子:
int (Screen::*pmfi)() = &Screen::height;
Screen& (Screen::*pmfS)( const Screen& ) = &Screen::copy;
Screen myScreen, *bufScreen;
// 直接调用成员函数
if ( myScreen.height() == bufScreen->height() )
bufScreen->copy( myScreen );
// 通过成员指针的等价调用
if ( (myScreen.*pmfi)() == (bufScreen->*pmfi)() )
(bufScreen->*pmfS)( myScreen );

类似地指向数据成员的指针可以按下列方式被访问:
typedef short Screen::*ps_Screen;
Screen myScreen, *tmpScreen = new Screen( 10, 10 );
ps_Screen pH = &Screen::_height;
ps_Screen pW = &Screen::_width;
tmpScreen->*pH = myScreen.*pH;
tmpScreen->*pW = myScreen.*pW;


4、静态类成员的指针:
    在非静态类成员的指针和静态类成员的指引之间有一个区别。指向类成员的指针语法不
能被用来引用类的静态成员静态类成员。是属于该类的全局对象和函数它们的指针是普通
指针。

如:
class A{
public :
static void f();
public:
static int m_data;
};

指向m_data指针的定义如下:
int *p = &A::m_data;

//错误
int A::* p = &A::m_data;
指向f函数指针可以这样定义:它是一个普通的函数指针
void (*ptrf)() = &A::f;


评论