Работа с указателями на члены класса
К указателям на члены класса можно обращаться только с помощью конкретного объекта или указателя на объект типа класса. Для этого применяется любой из двух операторов доступа (.* для объектов класса и ссылок на них или ->* для указателей). Например, так вызывается функция-член через указатель на нее:
int (Screen::*pmfi)() = &Screen::height; Screen& (Screen::*pmfS)( const Screen& ) = &Screen::copy; Screen myScreen, *bufScreen; // прямой вызов функции-члена if ( myScreen.height() == bufScreen->height() ) bufScreen->copy( myScreen ); // эквивалентный вызов по указателю if ( (myScreen.*pmfi)() == (bufScreen->*pmfi)() ) |
(bufScreen->*pmfS)( myScreen );
Вызовы
(myScreen.*pmfi)() |
(bufScreen->*pmfi)();
требуют скобок, поскольку приоритет оператора вызова () выше, чем приоритет взятия указателя на функцию-член. Без скобок
myScreen.*pmfi()
интерпретируется как
myScreen.*(pmfi())
Это означает вызов функции pmfi() и привязку возвращенного ей значения к оператору (.*). Разумеется, тип pmfi не поддерживает такого использования, так что компилятор выдаст сообщение об ошибке.
Указатели на данные-члены используются аналогично:
typedef short Screen::*ps_Screen; Screen myScreen, *tmpScreen = new Screen( 10, 10 ); ps_Screen pH = &Screen::_height; ps_Screen pW = &Screen::_width; tmpScreen->*pH = myScreen.*pH; |
tmpScreen->*pW = myScreen.*pW;
Приведем реализацию функции-члена repeat(), которую мы обсуждали в начале этого раздела. Теперь она будет принимать указатель на функцию-член:
typedef Screen& (Screen::Action)(); Screen& Screen::repeat( Action op, int times ) { for ( int i = 0; i < times; ++i ) (this->*op)(); return *this; |
}
Параметр op – это указатель на функцию-член, которая должна вызываться times
раз.
Если бы нужно было задать значения аргументов по умолчанию, то объявление repeat() выглядело бы следующим образом:
class Screen { public: Screen &repeat( Action = &Screen::forward, int = 1 ); // ... |
А ее вызовы так:
Screen myScreen; myScreen.repeat(); // repeat( &Screen::forward, 1 ); |
Определим таблицу указателей. В следующем примере Menu – это таблица указателей на функции- члены класса Screen, которые реализуют перемещение курсора. CursorMovements – перечисление, элементами которого являются номера в таблице Menu.
Action::Menu() = { &Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down, &Screen::end }; enum CursorMovements { HOME, FORWARD, BACK, UP, DOWN, END |
Можно определить перегруженную функцию-член move(), которая принимает параметр CursorMovements и использует таблицу Menu для вызова указанной функции-члена. Вот ее реализация:
Screen& Screen::move( CursorMovements cm ) { ( this->*Menu[ cm ] )(); return *this; |
У оператора взятия индекса ([]) приоритет выше, чем у оператора указателя на функцию-член (->*). Первая инструкция в move()
сначала по индексу выбирает из таблицы Menu
нужную функцию-член, которая и вызывается с помощью указателя this и оператора указателя на функцию-член. move() можно применять в интерактивной программе, где пользователь выбирает вид перемещения курсора из отображаемого на экране меню.