13.6.2. Работа с указателями на члены класса

13.6.2. Работа с указателями на члены класса

К указателям на члены класса можно обращаться только с помощью конкретного объекта или указателя на объект типа класса. Для этого применяется любой из двух операторов доступа (.* для объектов класса и ссылок на них или -* для указателей). Например, так вызывается функция-член через указатель на нее:

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

Параметр op – это указатель на функцию-член, которая должна вызываться times раз.

Если бы нужно было задать значения аргументов по умолчанию, то объявление repeat() выглядело бы следующим образом:

class Screen {

public:

Screen &repeat( Action = &Screen::forward, int = 1 );

// ...

};

А ее вызовы так:

Screen myScreen;

myScreen.repeat(); // repeat( &Screen::forward, 1 );

myScreen.repeat( &Screen::down, 20 );

Определим таблицу указателей. В следующем примере 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() можно применять в интерактивной программе, где пользователь выбирает вид перемещения курсора из отображаемого на экране меню.