// Этот typedef делает программный код более понятным
typedef bool (*FuncPtrBoolInt)(int);
// Функция, которая выполняется достаточно длительное время
void longOperation(FuncPtrBoolInt f) {
for (long l=0; l < 100000000; l++)
if (l % 10000000 == 0)
f(l/1000000);
}
int main {
longOperation(updateProgress); //
нормально
}
Обсуждение
В ситуации, которая показана в примере 15.1, применение указателя на функцию является хорошим решением, если
UpdateProgress
и
longOperation
ничего не должны знать друг о друге. Например, функцию, которая обновляет индикатор состояния процесса в диалоговом окне пользовательского интерфейса (user interface — UI), в окне консольного режима или где-то еще, не заботит контекст, в котором она вызывается. Аналогично функция
longOperation
может быть частью некоторого программного интерфейса загрузки данных, которого не заботит место вызова: из графического UI, из окна консольного режима или из фонового процесса.
Сначала потребуется определить сигнатуру функции, которую вы планируете вызывать, и создать для нее
typedef
. Оператор
typedef
— ваш помощник в тех случаях, когда приходится иметь дело с указателями функций, потому что они имеют не очень привлекательный синтаксис. Рассмотрим, как обычно объявляется такой указатель на примере переменной
f
, которая содержит адрес функции, принимающей единственный аргумент целого типа и возвращающей значения типа
boolean
. Это может выглядеть следующим образом
bool (*f)(int); // f - имя переменной
Вы можете справедливо возразить, что здесь нет ничего особенного и я просто излишне драматизирую ситуацию. Но что вы скажете, если требуется определить вектор
vector
таких указателей?
vector<bool (*)(int)> vf;
Или их массив?
bool (*af[10])(int);
Форма представления указателей на функции отличается от обычных переменных С++, которые обычно задаются в виде (квалифицированного) имени типа, за которым идет имя переменной. Поэтому они вносят путаницу при чтении программного кода.
Итак, в примере 15.1 я использовал следующий
typedef
.
typedef bool (*FuncPtrBoolInt)(int);
Сделав это, я могу свободно объявлять указатели функций с сигнатурой, возвращающей значение
bool
и принимающей единственный аргумент, как это я бы делал для параметра любого другого типа, например.
void longOperation(FuncPtrBoolInt f) { // ...
Теперь все, что надо сделать в
longOperation
, — это вызвать
f
,
как если бы это была любая обычная функция.
f(l/1000000);
Таким образам, здесь
f
может быть любой функцией, которая принимает аргумент целого типа и возвращает
bool
. Предположим, что в вызывающей функции
longOperation
не требуется обеспечивать продвижение индикатора состояния процесса. Тогда ей можно передать указатель на функцию без операций.
bool whoCares(int i) {return(true);}
//...
longOperation(whoCares);
Более важно то, что выбор функции, передаваемой
longOperation
, может осуществляться динамически на этапе выполнения.
15.2. Применение указателей для членов класса
Проблема
Требуется обеспечить адресную ссылку на данное-член или на функцию-член.
Решение
Используйте имя класса и оператор области видимости (
::
) со звездочкой для правильного квалифицирования имени. Пример 15.2 показывает, как это можно сделать.
Пример 15.2. Получение указателя на член класса
#include <iostream>
#include <string>
class MyClass {
public:
MyClass : ival_(0), sval_("foo") {}
~MyClass {}
void incr {++ival_;}
void decr {ival_--;}
private:
std::string sval_;
int ival_;
};
int main {
MyClass obj;
int MyClass::* mpi = &MyClass::ival_; // Указатели на