вносят путаницу при чтении программного кода.

Итак, в примере 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_;         // Указатели на

 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)();

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату