Screen.h
#ifndef SCREEN_H #define SCREEN_H #include <string> class Screen { public: typedef std::string::size_type pos; // Action is a type that can point to a member function of Screen // that returns a reference to a Screen and takes no arguments using Action = Screen&(Screen::*)(); // constructor: build screen of given size containing all blanks Screen(pos ht = 0, pos wd = 0): contents(ht * wd, ' '), cursor(0), height(ht), width(wd) { } friend int main(); // data is a static member that returns a pointer to member static const std::string Screen::*data() { return &Screen::contents; } char get_cursor() const { return contents[cursor]; } char get() const { return contents[cursor]; } inline char get(pos ht, pos wd) const; private: std::string contents; pos cursor; pos height, width; public: // cursor movement functions // beware: these functions don't check whether the operation is valid Screen& home() { cursor = 0; return *this; } Screen& forward() { ++cursor; return *this; } Screen& back() { --cursor; return *this; } Screen& up() { cursor += height; return *this; } Screen& down() {cursor -= height; return *this; } // specify which direction to move; enum see XREF(enums) enum Directions { HOME, FORWARD, BACK, UP, DOWN }; Screen& move(Directions); private: static Action Menu[]; // function table }; char Screen::get(pos r, pos c) const // declared as inline in the class { pos row = r * width; // compute row location return contents[row + c]; // return character at the given column } inline Screen& Screen::move(Directions cm) { // run the element indexed by cm on this object return (this->*Menu[cm])(); // Menu[cm] points to a member function } #endif
Screen.cpp
#include "Screen.h" Screen::Action Screen::Menu[] = { &Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down, };
useScreen.cpp
#include "Screen.h" #include <functional> using std::function; #include <iostream> using std::cout; using std::endl; #include <string> using std::string; struct X { int foo(int i) { cout << "foo(" << i << ")" << endl; return i; } }; void xfcn() { function<int (X*, int)> f; f = &X::foo; // pointer to member X x; int v = f(&x, 5); cout << "v = " << v << endl; } int main () { // pdata can point to a string member of a const (or nonconst) Screen const string Screen::*pdata; // uninitialized pdata = &Screen::contents; // points to the contents member auto pdata2 = &Screen::contents; // equivalent declaration // data() returns a pointer to the contents member of class Screen const string Screen::*pdata3 = Screen::data(); // Screen objects Screen myScreen, *pScreen = &myScreen; const Screen cScreen, *pcScreen = &cScreen; // .* dereferences pdata to fetch the contents member // from the object myScreen auto str = myScreen.*pdata; // s is a string auto cstr = cScreen.*pdata; // c is a const string // ->* dereferences pdata to fetch contents // from the object to which pScreen points str = pScreen->*pdata; // pmf is a pointer that can point to a Screen member function // that takes no arguments, returns a char, and is const // that returns a char and takes no arguments auto pmf = &Screen::get_cursor; char (Screen::*pmf2)() const = &Screen::get; // same type as pmf pmf = &Screen::get; // which version of get deduced from type of pmf pmf2 = &Screen::get_cursor; Screen s; char c1 = s.get_cursor(); // gets character at the cursor directly char c2 = (s.*pmf2)(); // calls get_cursor indirectly through pmf2 // call the function to which pmf points // on the object to which pScreen points c1 = (pScreen->*pmf)(); // pmf3 points to the two-parameter version of get char (Screen::*pmf3)(Screen::pos, Screen::pos) const = &Screen::get; c1 = myScreen.get(0,0); // call two-parameter version of get c2 = (myScreen.*pmf3)(0,0); // equivalent call to get // Op is a type that can point to a member function of Screen // that returns a char and takes two pos arguments using Op = char (Screen::*)(Screen::pos, Screen::pos) const; // equivalent declaration of Op using a typedef typedef char (Screen::*Op)(Screen::pos, Screen::pos) const; Op get = &Screen::get; // get points to the get member of Screen myScreen.move(Screen::HOME); // invokes myScreen.home myScreen.move(Screen::DOWN); // invokes myScreen.down // bind an object of type function to a pointer to member function<char (const Screen*)> f = &Screen::get_cursor; return 0; }