вносят путаницу при чтении программного кода.
Итак, в примере 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 показывает, как это можно сделать.
#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_; // Указатели на
std::string MyClass::* mps = &MyClass::sval_; // данные-члены
void (MyClass::*mpf)(); // Указатель на функцию-член, у которой
// нет параметров и которая возвращает void
void (*pf)(); // Обычный указатель на функцию
int* pi = &obj.ival_; // int-указатель, ссылающийся на переменную-член
// типа int, - все нормально.
mpf = &MyClass::incr; // Указатель на функцию-член. Вы не можете
// записать это значение в поток. Посмотрите в
// отладчике, как это значение выглядит.
pf = &MyClass::incr; // Ошибка: &MyClass::inc не является экземпляром
// функции
std::cout << 'mpi = ' << mpi << '
';
std::cout << 'mps = ' << mps << '
';
std::cout << 'pi = ' << pi << '
';
std::cout << '*pi = ' << *pi << '
';
obj.*mpi = 5;
obj.*mps = 'bar';
(obj.*mpf)(); // теперь obj.ival_ равно 6
std::cout << 'obj.ival_ = ' << obj.ival_ << '
';
std::cout << 'obj.sval_ = ' << obj.sval_ << '
';
}
Указатели на члены класса выглядят и работают иначе, чем обычные указатели. Прежде всего, они имеют «смешной» синтаксис (не вызывающий смех, но странный). Рассмотрим следующую строку из примера 15.2.
int MyClass::* mpi = &MyClass::ival_;
Здесь объявляется указатель и ему присваивается значение целого типа, которым оказывается член класса MyClass
. Две вещи отнимают это объявление от обычного int*
. Во- первых, вам приходится вставлять имя класса и оператор области видимости между типом данного и звездочкой. Во-вторых, при выполнении операции присваивания этому указателю на самом деле не назначается какой то определенный адрес памяти. Значение &MyClass::ival_
не является каким-то конкретным значением, содержащимся в памяти; оно ссылается на имя
Переменная mpi
должна использоваться совместно с экземпляром класса, к которому она применяется. Немного ниже в примере 15.2 располагается следующая строка, которая использует mpi
для присваивания целого числа значению, на которое ссылается указатель mpi
.
obj.*mpi = 5;
obj
является экземпляром класса MyClass
. Ссылка на член с использованием точки (или ->
, если у вас имеется указатель на obj
) и разыменование mpi
позволяют вам получить ссылку на obj.ival_
.
Указатели на функции-члены действуют фактически так же. В примере 15.2 объявляется указатель на функцию-член MyClass
, которая возвращает void
и не имеет аргументов.
void (MyClass::*mpf)();
Ему можно присвоить значение с помощью оператора адресации.
mpf = &MyClass::incr;
Для вызова функции заключите основное выражение в скобки, чтобы компилятор понял ваши намерения, например:
(obj.*mpf)();