c++ - c++ pointer to member classes

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])();
}
 

 

 

 

你可能感兴趣的:(C++)