you can define members to class members, either classes data members or class method members.
there is onething that makes the pionter to member function different from other normal ponters.
A pointer to member function must first be bound to an object or a pionter to obtain a this pointer for function invocation before the function to which it refers can be called.
The type of the Pionter to data member is as follow.
// below shows you how to define // "a pointer to member of class Screen of type short." // short Screen::*
and below shows some declaration of pointer to data members to class Screen.
int Screen::*ps_Screen = &Screen::_height; ps_Screen = &Screen::_width;
and if you wan to declare some pointer to member methods.
// if you want to declare // a pointer to Screen member function capaple of referring to the mbme rfunction height() and width() is as follow int (Screen::*) (); // e.g. int (Screen::*pmf1)() = 0; int (Screen::*pmf2)() = &Screen::height; pmf1 = pmf2; pmf2 = &Screen::width;
the pointer to member functions are types, which you can typedef to something else, here is the code.
typedef Screen& (Screen::*Action)(); Action _default = &Screen::home; Action next = &Screen::forward;
As we said before, to invoke a pionter to member function, you should have a class object or pointer to to obtain the 'this' pointer, here is a simple case from the client's perspective on how to invoke the pointer to member function.
// below shows how you can invoke method through the pointer to member methods Screen myScreen; typedef Screen& (Screen::*Action)(); Action _default = &Screen::home; extern Screen& action(Screen&, Action = &Screen::display); void ff() { action(myScreen); action(myScreen, _default); action(myScreen, &Screen::end); }
Below is the code that shows you how to invoke the pionter to member functions from the devloper's perspective.
//invocation of the pointer to class member // int (Screen::*pmfi) () = &Screen::height; Screen& (Screen::*pmfS)(const Screen&) = &Screen::copy; Screen myScreen, *bufScreen; // direct invocation of the member function if (myScreen.height() == bufScreen->height() ) bufScreen->copy(myScreen); // equivalent invocation through the pointer to member function if ( (myScreen.*pmfi)() == (bufScreen->*pmfi()()) { (bufScreen->*pmfS)(myScreen); }
Similarily , you can expect the following works for the pionter to data members.
typedef int Screen::*ps_Screen; Screen myScreen, *tmpScreen = new Screen(10, 10); ps_Screen pH = &Screen::_height; ps_Screen pW = &Screen::_width; tempScreen->*pH = myScreen.*pH; tempScreen->*pW = myScreen.*pW;
With the help of Pointer to member functions, you can abtract and simplifies your code greatly, suppose we have a move method for the Screen class, and the move method should performs various action, instead of writting a huge switch case, you can do this:
class Screen { private: typedef Screen& (Screen::*Action)(); //Action (*Menu)[6]; // this is a pointer to pionter to an array of 6 //Action *Menu[6]; // this is a array of pointer, size of 6, the same as Action (*Menu[6]); static Action Menu[6]; enum CursorMovements { HOME, FORWARD, BACK, UP, DOWN, END }; public: // below we are going to show the importance of the function as pointer to members Screen& repeat(Action op, int times); Screen& move(CursorMovements cm); } Screen::Action Screen::Menu[6] = { &Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down, &Screen::end }; inline Screen& Screen::repeat(Action op, int times) { for (int i = 0; i < times; ++i) { (this->*op)(); } return *this; } inline Screen& Screen::move(CursorMovements cm) { return (this->*Menu[cm])(); }
the complete code is as follow.
#include <string> #include <iostream> #include <fstream> #include <functional> #include <iterator> #include <algorithm> #include <cstring> using std::string; using std::fstream; using std::copy; using std::cout; using std::endl; using std::cerr; using std::strcpy; using std::strcat; using std::istream; using std::ostream; namespace { class Screen { private: typedef Screen& (Screen::*Action)(); //Action (*Menu)[6]; // this is a pointer to pionter to an array of 6 //Action *Menu[6]; // this is a array of pointer, size of 6, the same as Action (*Menu[6]); static Action Menu[6]; enum CursorMovements { HOME, FORWARD, BACK, UP, DOWN, END }; public: // constructor inline Screen(int hi = 8, int wid = 40, char bk = '*'); inline Screen& home() { _cursor = 0; return *this; } void move(int, int); void move(int , int ) const; char get() { return _screen[_cursor]; } inline char get(int, int ); bool checkRange(int, int) const; int height() { return _height; } int width() { return _width;} // inline Screen& forward(); inline Screen& back(); inline Screen& end(); inline Screen& up(); inline Screen& down(); inline int row(); // not defined, we might go to that later. friend istream& operator >>(istream &, Screen &) ; friend ostream& operator <<(ostream&, const Screen &) ; void copy(const Screen & obj); inline void set(const string &s); inline void set(char s); // below we are going to show the importance of the function as pointer to members Screen& repeat(Action op, int times); Screen& move(CursorMovements cm); private: inline int remainingSpace(); string _screen; // from the above declaration below, to allow the move method to be called from a const object //string::size_type _cursor; mutable string::size_type _cursor; int _height; int _width; /*static const int _height = 24; static const int _width =80;*/ static const int BELL = '\007'; }; void Screen::copy(const Screen &obj) { /// fif this Screen object and objs are the same objcet // no copy necessary /// we look at hte 'this ' pointer if (this != &obj) { _height = obj._height; _width =obj._width; _cursor = 0; // create a new string // its content is the same as obj._screen _screen = obj._screen; } } bool Screen::checkRange(int row, int col) const { if (row < 1 || row > _height || col < 1 || col > _width ) { cerr << "Screen coordinates (" << row << ", " << col << " ) out of bounds.\n"; return false; } return true; // a better way is to write as such //return !((row < 1 || row > _height || col < 1 || col > _width)); } inline void Screen::move(int r, int c) { // move _cursor to absolute position if (checkRange(r, c) ) { int row = ( r - 1) * _width; // row location _cursor = row + c - 1; } } inline void Screen::move(int r, int c) const { // can we directly call the Screen::move method or can we ask the Screen::move(int r, int c) to call the (Screen::move(int r, int c) const" method if (checkRange(r, c)) { int row = (r - 1) * _width; _cursor = row + c - 1; // because now the _cursor is mutable members, it does not matter if you call it from a const contetxt } } // a side note, inline declaration should be placed // in the header file. normally you will carry the inline keyword with you . inline char Screen::get(int r, int c) { move(r, c); return get(); } inline void Screen::set(const string &s) { // write string beginning at current _cursor position int space = remainingSpace(); int len = s.size(); if (space < len) { cerr << "Screen: warning: truncate: " << "space: " << space << "string length: " << len << endl; } } inline void Screen::set(char ch) { if (ch == '\0') { cerr << "Screen: Warning: " << "Null character (ignored).\n"; } else { _screen[_cursor] = ch; } } inline int Screen::remainingSpace() { // currrent position is no longer remaining int sz = _width * _height; return (sz - _cursor); } inline Screen::Screen(int hi, int wid, char bk) : _height (hi), _width(wid), _cursor(0), _screen(hi * wid, bk) { // all the work is done with the number initialize list } Screen::Action Screen::Menu[6] = { &Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down, &Screen::end }; inline Screen& Screen::forward() { ++_cursor; // check if top of screen: wrap around if (_cursor == 0) { home(); } return *this; } inline Screen& Screen::back() { // move _cursor backward one screen element // check for opt of screen: wrap around if (_cursor == 0) { end(); } else --_cursor; return *this; } inline Screen& Screen::end() { _cursor = _width * _height - 1; return *this; } inline Screen& Screen::up() { // move _cursor up one row of screen // do not wrap around; rather, ring bells if (row() == 1) // at top ? cout << BELL << endl; else _cursor -= _width; return *this; } inline Screen& Screen::down() { if (row() == _height) // at bottom? cout << BELL << endl; else _cursor += _width; return *this; } inline int Screen::row() { return (_cursor + _width) / _width; } inline Screen& Screen::repeat(Action op, int times) { for (int i = 0; i < times; ++i) { (this->*op)(); } return *this; } inline Screen& Screen::move(CursorMovements cm) { return (this->*Menu[cm])(); }