类成员指针

我们知道,给定对象的指针,可以使用箭头(->)操作符从该对象获得给定成员但是 , 有时从成员开始是有用的,也就是说,我们希望获得特定成员的指针,然后从一个对象或别的对象获得该成员 注意:成员指针只应用于非 static 成员。static类成员不是任何对象的组成部分,所以不需要特殊语法指向static 成员,static成员指针时普通指针

一、

声明成员指针

1
2
3
4
5
6
7
8
9
10
11
class Screen
{
public:
typedef std::string::size_type index;
char get() const;
char get(index ht , index wd) const;
private:
std::string contents;
index cursor;
index height , width;
};

由类定义可以看出,成员contents的完全类型为 “类Screen的成员 , 其类型为std::string”因此,可以指向contents的指针的完全类型是“指向std::string类型的Screen类成员的指针”这个类型可以写为:

1
string Screen::*

定义为: string Screen::*ps_Screen;

contents的地址初始化ps_Screen,代码为:

1
string Screen::*ps_Screen = &Screen::contents;

同样 , 还可以将指向height ,width, cursor成员的指针定义为:

1
Screen::index Screen::*pindex;

初始化(用width

1
pindex = & Screen::width;

定义成员函数的指针

成员函数的指针必须在三个方面与它所指函数的类型相匹配

  1. 函数形参类型和数目,包括成员是否是const
  2. 返回类型
  3. 所属类的类型

例如,可引用不接受形参的get版本的Screen成员函数的指针具有如下类型

1
char (Screen::*) () const

用成员初始化该指针:

1
char (Screen::*pmf)()const = &Screen::get;

也可以将带两个形参的get函数版本的指针定义为:

1
2
char (Screen::*pmf2)(Screen::index , Screen::index) const;
pmf2 = &Screen::get;

为成员指针使用类型别名

使用类型别名(typedef)可以使成员指针更容易阅读。例如:

1
2
typedef
char (Screen::*Action)(Screen::index , Screen::index) const;

Action 是类型“Screen类的接受两个index类型形参并返回char的成员函数的指针”的名字
例如:

1
Action get = &Screen::get;

可以使用成员指针函数类型来声明函数形参和函数的返回类型:

1
Screen& action(Screen & , Action = &Screen:get);

使用该函数:

1
2
3
4
Screen myScreen;
action(myScreen);
action(myScreen , get);
action(myScreen , &Screen::get);//传址调用

二、

使用类成员的指针

类似于成员访问操作符.-> , .*->*是两个新的操作符,它们是使我们能够将成员指针绑定到实际对象

这两个操作符的左操作数必须是类类型的对象或类类型的指针 , 右操作数是该类型的成员指针

  • *成员指针解引用操作符(.*)从对象或引用获取成员
  • * 成员指针箭头操作符(->*)通过对象的指针获取成员

使用成员函数的指针

实例:调用Screen中不带形参的get版本

1
2
3
4
5
6
7
char (Screen::*pmf)()const = &Screen::get;
Screen myScreen;
char c1 = myScreen.get();
char c2 = (myScreen.*pmf)();
Screen *pScreen = &myScreen;
c1 = pScreen->get();
c2 = (pScreen->*pmf)();

调用含实参版本的get

1
2
3
4
5
char (Screen::*pmf2)(Screen::index , Screen::index) const ;
pmf2 = &Screen::get;
Screen myScreen;
char c1 = myScreen.get(0 ,0);
char c2 = myScreen.*get(0 , 0);

使用数据成员的指针

相同的成员指针操作符用于访问数据成员

1
2
3
4
5
6
7
8
9
Screen::index Screen::*pindex = &Screen::width;
Screen myScreen;
Screen::index ind1 = myScreen.width;
Screen::index ind2 = myScreen.*pindex;
Screen *pScreen = &myScreen;
ind1 = pScreen->width;
ind2 = pScreen->*pindex;

成员函数表

函数指针和成员函数指针的一个公共用途是:将它们存储在函数表中。函数表示函数指针的集合,在运行时从中选择给定调用

对几个相同类型的成员的类而言, 可以使用这样的表来从这些成员的集合中选择一个。
实例:

1
2
3
4
5
6
7
8
9
class Screen
{
public:
Screen& home();
Screen& forward();
Screen& back();
Screen& up();
Screen& down();
};

使用函数指针表

下面是函数表的经典使用方法:

1
2
3
4
5
6
7
8
9
10
class Screen
{
public:
//部分缺省,就是利用上面么
typedef Screen& (Screen::*Action)();
static Action Menu[];//这个定义得再类体外
public:
enum Directions{ HOME , FORWARD , BACK , UP , DOWN};
Screen& move(Directions);
};

名为Menu的数组将保存指向每个光标移动函数的指针,将在对应于Directions中枚举成员的偏移位置保存函数

move函数接受枚举成员并调用适当的函数

1
2
3
4
5
Screen& Screen::move(Directions cm)
{
(this->*Menu[cm])();//运行指向的函数
return *this;
}

当然静态成员定义是必须的啦:

1
2
3
4
5
6
Screen::Action Screen::Menu[] = {
Screen& home();
Screen& forward();
Screen& back();
Screen& up();
Screen& down();};

使用示例:

1
2
3
Screen myScreen;
myScreen.move(Screen::HOME);
myScreen.move(Screen::DOWN);

热评文章