首页 > 代码库 > C++ Primer 学习笔记_103_特殊工具与技术 --类成员指针
C++ Primer 学习笔记_103_特殊工具与技术 --类成员指针
特殊工具与技术
--类成员指针
成员指针可以做到:获得特定成员的指针,然后从一个对象或别的对象获得该成员.成员指针应该包含类的类型以及成员的类型.
一.声明成员指针
测试类:
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; };
1.定义数据成员指针
contents 的完全类型是“Screen 类的成员, 其类型是 std::string”。 因此, 可以指向 contents 的指针的完全类型是“指向 std::string 类型的 Screen 类成员的指针”,可以将指向 Screen 类的 string 成员的指针定义为
std::string Screen::*ps_Screen;
可以用contents的地址初始化ps_Screen
std::string Screen::*ps_Screen = &Screen::contents;
还可以将height,width或cursor成员的指针定义为:
Screen::index Screen::*pindex;
这是说,pindex 是具有 Screen::index 类型的 Screen 类成员的指针。可以将 width 的地址赋给这个指针
pindex = &Screen::height; pindex = &Screen::width;
2.定义成员函数的指针
通过指定函数返回类型、形参表和类来定义成员函数的指针。例如,可引用不接受形参的 get 版本的 Screen 成员函数的指针具有如下类型:
char (Screen::*)() const;
这个get函数版本的指针可以定义和初始化如下:
char (Screen::*pmf)() const = &Screen::get;
也可以将带两个形参的 get 函数版本的指针定义为
char (Screen::*pmfTwoRef)(Screen::index,Screen::index) const; pmfTwoRef = &Screen::get;
[小心!]
调用操作符的优先级高于成员指针操作符,因此,包围Screen::* 的括号是必要的,没有这个括号,编译器就将下面代码当作(无效的)函数声明:
// error: non-member function p cannot have const qualifier char Screen::*p() const;
3.为成员指针使用类型别名
类型别名可以使成员指针更容易阅读。
typedef char (Screen::*Action)(Screen::index,Screen::index) const;
Action 是类型“Screen 类的接受两个 index 类型形参并返回 char 的成员函数的指针”的名字。使用类型别名,可以将 get 指针的定义简化为
Action get = &Screen::get;
也可以使用成员指针函数类型来声明函数形参和函数的返回类型:
Screen &action(Screen &,Action = &Screen::get);
可以通过传递Screen类中适当成员函数的指针或地址调用action函数:
Screen myScreen; action(myScreen); action(myScreen,get); action(myScreen,&Screen::get);
二.使用类成员的指针
类似于成员访问操作符 . 和 ->,.* 和 -> 是两个新的操作符,它们使我们能够将成员指针绑定到实际对象。 这两个操作符的左操作数必须是类类型的对象或类类型的指针,右操作数是该类型的成员指针。
? 成员指针解引用操作符(.*)从对象或引用获取成员。
? 成员指针箭头操作符(->*)通过对象的指针获取成员。
1.使用成员函数的指针
char (Screen::*pmf)() const = &Screen::get; Screen myScreen; char ch1 = myScreen.get(); char ch2 = (myScreen.*pmf)(); //equivalent call to get Screen *pMyScreen = &myScreen; ch1 = pMyScreen -> get(); ch2 = (pMyScreen ->* pmf)(); //equivalent call to get //使用带有参数的版本 char (Screen::*pmfTwoRef)(Screen::index,Screen::index) const = &Screen::get; ch1 = myScreen.get(0,0); ch2 = (myScreen.*pmfTwoRef)(0,0); //equivalent call to get
[小心!]
因为调用操作符(())比成员指针操作符优先级高,所以调用(myScreen.*pmf)() 和 (pScreen->*pmf)() 需要括号。
2.使用数据成员的指针
Screen::index Screen::*pIndex = &Screen::width; Screen myScreen; Screen::index index1 = myScreen.width; Screen::index index2 = myScreen.*pIndex; Screen *pMyScreen = &myScreen; index1 = pMyScreen -> width; index2 = pMyScreen ->* pIndex;
3.成员指针函数表
函数指针和成员函数指针的一个公共用途:将它们存储在函数表中.函数表是函数指针的集合,在运行时从中选择给定调用.
对具有几个相同类型成员的类而言,可以使用这样的表来从这些成员的集合中选择一个。如:
class Screen { public: Screen &home(); Screen &forward(); Screen &back(); Screen &up(); Screen &down(); private: //... };
这些新函数都不接受形参,并返回调用它的的对象的引用.
4.使用函数指针表
我们可能希望定义一个 move 函数,它可以调用这些函数中的任意一个并执行指定动作。 为了支持这个新函数, 我们将在 Screen 中增加一个 static 成员,该成员是光标移动函数的指针的数组:
class Screen { public: //As Before typedef Screen &(Screen::*Action)(); static Action Menu[]; //函数表 public: enum Directions {HOME,FORWARD,BACK,UP,DOWN}; //决定往哪方向移动 Screen &move(Directions); private: //As Before };
名为Menu的数组将保存指向每个光标移动函数的指针,将在对应于Directions中枚举成员的偏移位置保存那些函数,move函数接受枚举成员并调用适当函数:
Screen& Screen::move(Directions cm) { (this ->* Menu[cm])(); return *this; }
这样计算move内部的调用:获取由cm索引的Menu元素(该元素师Screen类成员函数的指针),代表 this 指向的对象调用该元素指向的成员函数。
Screen myScreen; myScreen.move(Screen::HOME); myScreen.move(Screen::UP);
5.定义成员函数指针表
//定义和初始化表本身 Screen::Action Screen::Menu[] = { &Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down };
//P657 习题18.26~27 Screen::index Screen::*pCursor = &Screen::cursor; typedef char (Screen::*pGetNoRef)() const; typedef char (Screen::*pGetTwoRef)() const; typedef Screen &(Screen::*pMoveNoRef)(); typedef Screen &(Screen::*pMoveTwoRef)();
//习题18.28~31 类定义如下 class Screen { public: typedef std::string::size_type index; typedef Screen& (Screen::*pFunNoRef)(); typedef Screen &(Screen::*Action)(); char get() const; char get(index ht,index wd) const; Screen &home(); Screen &forward(); Screen &back(); Screen &up(); Screen &down(); private: static Action Menu[]; public: Screen(pFunNoRef rf = &Screen::home):pmf(rf) {} void setPmf(pFunNoRef rf = &Screen::home) { pmf = rf; } enum Directions {HOME,FORWARD,BACK,UP,DOWN}; Screen &move(Directions); private: std::string contents; index cursor; index height,width; public: pFunNoRef pmf; };