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

class Screen {

public:

 // другие члены интерфейса и реализации, как прежде

 Screen& home(); // функции перемещения курсора

 Screen& forward();

 Screen& back();

 Screen& up();

 Screen& down();

};

Каждая из этих новых функций не получает никаких параметров и возвращает ссылку на вызвавший ее объект класса Screen.

Можно определить функцию move(), способную вызвать любую из этих функций и выполнить указанное действие. Для поддержки этой новой функции в класс Screen добавлен статический член, являющийся массивом указателей на функции перемещения курсора:

class Screen {

public:

 // другие члены интерфейса и реализации, как прежде

 // Action - указатель, который может быть присвоен любой из

 // функций-членов перемещения курсора

 using Action = Screen&(Screen::*)();

 // задать направление перемещения;

 // перечисления описаны в разделе 19.3

 enum Directions { HOME, FORWARD, BACK, UP, DOWN };

 Screen& move(Directions);

private:

 static Action Menu[]; // таблица функций

};

Массив Menu содержит указатели на каждую из функций перемещения курсора. Эти функции будут храниться со смещениями, соответствующими перечислителям перечисления Directions. Функция move() получает перечислитель и вызывает соответствующую функцию:

Screen& Screen::move(Directions cm) {

 // запустить элемент по индексу cm для объекта this

 return (this->*Menu[cm])(); // Menu[cm] указывает на функцию-член

}

Вызов move() обрабатывается следующим образом: выбирается элемент массива Menu по индексу cm. Этот элемент является указателем на функцию-член класса Screen. Происходит вызов функции-члена, на которую указывает этот элемент от имени объекта, на который указывает указатель this.

Когда происходит вызов функции move(), ему передается перечислитель, указывающий направление перемещения курсора:

Screen myScreen;

myScreen.move(Screen::HOME); // вызывает myScreen.home

myScreen.move(Screen::DOWN); // вызывает myScreen.down

Остается только определить и инициализировать саму таблицу:

Screen::Action Screen::Menu[] = { &Screen::home,

                                  &Screen::forward,

                                  &Screen::back,

                                  &Screen::up,

                                  &Screen::down,

};

Упражнения раздела 19.4.2

Упражнение 19.14. Корректен ли следующий код? Если да, то что он делает? Если нет, то почему?

auto pmf = &Screen::get_cursor; pmf = &Screen::get;

Упражнение 19.15. В чем разница между обычным указателем на функцию и указателем на функцию-член?

Упражнение 19.16. Напишите псевдоним типа, являющийся синонимом для указателя, способного указать на переменную-член avgprice класса Sales_data.

Упражнение 19.17. Определите псевдоним типа для каждого отдельного типа функции-члена класса Screen.

<p>19.4.3. Использование функций-членов как вызываемых объектов</p>

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

Поскольку указатель на член класса не является вызываемым объектом, нельзя непосредственно передать указатель на функцию-член алгоритму. Например, если необходимо найти первую пустую строку в векторе строк, вполне очевидный вызов не сработает:

auto fp = &string::empty; // fp указывает на функцию empty()

                          // класса string

Перейти на страницу:

Похожие книги