Как правило, перед использованием указатели на функции и указатели на функции-члены хранят в таблице функций (см. раздел 14.8.3). Когда у класса есть несколько членов того же типа, такая таблица применяется для выбора одного из набора этих членов. Предположим, что класс Screen дополнен несколькими функциями-членами, каждая из которых перемещает курсор в определенном направлении:
class Screen {
public:
//
Screen& home(); //
Screen& forward();
Screen& back();
Screen& up();
Screen& down();
};
Каждая из этих новых функций не получает никаких параметров и возвращает ссылку на вызвавший ее объект класса Screen
.
Можно определить функцию move()
, способную вызвать любую из этих функций и выполнить указанное действие. Для поддержки этой новой функции в класс Screen
добавлен статический член, являющийся массивом указателей на функции перемещения курсора:
class Screen {
public:
//
//
//
using Action = Screen&(Screen::*)();
//
//
enum Directions { HOME, FORWARD, BACK, UP, DOWN };
Screen& move(Directions);
private:
static Action Menu[]; //
};
Массив Menu
содержит указатели на каждую из функций перемещения курсора. Эти функции будут храниться со смещениями, соответствующими перечислителям перечисления Directions
. Функция move()
получает перечислитель и вызывает соответствующую функцию:
Screen& Screen::move(Directions cm) {
//
return (this->*Menu[cm])(); //
}
Вызов move()
обрабатывается следующим образом: выбирается элемент массива Menu
по индексу cm
. Этот элемент является указателем на функцию-член класса Screen
. Происходит вызов функции-члена, на которую указывает этот элемент от имени объекта, на который указывает указатель this
.
Когда происходит вызов функции move()
, ему передается перечислитель, указывающий направление перемещения курсора:
Screen myScreen;
myScreen.move(Screen::HOME); //
myScreen.move(Screen::DOWN); //
Остается только определить и инициализировать саму таблицу:
Screen::Action Screen::Menu[] = { &Screen::home,
&Screen::forward,
&Screen::back,
&Screen::up,
&Screen::down,
};
Упражнение 19.14. Корректен ли следующий код? Если да, то что он делает? Если нет, то почему?
auto pmf = &Screen::get_cursor; pmf = &Screen::get;
Упражнение 19.15. В чем разница между обычным указателем на функцию и указателем на функцию-член?
Упражнение 19.16. Напишите псевдоним типа, являющийся синонимом для указателя, способного указать на переменную-член avgprice
класса Sales_data
.
Упражнение 19.17. Определите псевдоним типа для каждого отдельного типа функции-члена класса Screen
.
19.4.3. Использование функций-членов как вызываемых объектов
Как уже упоминалось, для вызова через указатель на функцию-член, нужно использовать операторы .*
и ->*
для связи указателя с определенным объектом. В результате, в отличие от обычных указателей на функцию, указатель на функцию-член класса не является
Поскольку указатель на член класса не является вызываемым объектом, нельзя непосредственно передать указатель на функцию-член алгоритму. Например, если необходимо найти первую пустую строку в векторе строк, вполне очевидный вызов не сработает:
auto fp = &string::empty; //
//