Указатели функций-членов и наиболее быстрые делегаты C++ - Указатели функций-членов

ОГЛАВЛЕНИЕ

Указатели функций-членов

В программах C++ большинство функций являются функциями-членами; то есть, они являются частью класса. Вы не можете использовать обычный указатель функции, чтобы ссылаться на функцию-член; вместо этого вы должны использовать указатель функции-члена. Указатель функции-члена на функцию-член класса SomeClass, с теми же аргументами что и раньше, объявляется так:

float (SomeClass::*my_memfunc_ptr)(int, char *);
// Постоянные функции-члены объявляются так:
float (SomeClass::*my_const_memfunc_ptr)(int, char *) const;

Заметьте, что используется специальный оператор (::*), и что SomeClass – это часть объявления. Указатели функций-членов имеют ужасное ограничение: они могут указывать только на функции-члены одного класса. Есть различные типы указателей функций-членов для каждой комбинации аргументов, для двух постоянных типов и для каждого класса. В MSVC также есть различные типы для каждого из 4 различных соглашений о вызовах: __cdecl, __stdcall, __fastcall, and __thiscall. (__thiscall по умолчанию. Любопытно, что нет зарегистрированного ключевого слова __thiscall, но оно иногда появляется в сообщениях об ошибках. Если вы используете его явно, то получите сообщение об ошибке, утверждающее, что оно зарезервировано для дальнейшего использования.) Если вы используете указатели функций-членов, вы всегда должны применять typedef, чтобы избежать путаницы.

Вы можете заставить ваш указатель функции ссылаться на функцию float SomeClass::some_member_func(int, char *) таким образом:

my_memfunc_ptr = &SomeClass::some_member_func;
 // Это синтаксис для операторов:
 my_memfunc_ptr = &SomeClass::operator !;
 // Нет пути получить адрес

Некоторые компиляторы (например, MSVC 6 и 7) позволят вам опустить &, даже если это не соответствует стандартам и создает путаницу. Более совместимые со стандартами компиляторы (например, GNU G++ и MSVC 8 (он же VS 2005)) требуют этого, поэтому вы должны указывать данный символ. Чтобы вызвать указатель функции-члена, вы должны создать экземпляр SomeClass, используя специальный оператор ->*. Этот оператор имеет низкий приоритет, поэтому его нужно заключить в круглые скобки:

  SomeClass *x = new SomeClass;
  (x->*my_memfunc_ptr)(6, "Another Arbitrary Parameter");
// Вы также можете использовать оператор .*, если ваш класс находится в стеке.
  SomeClass y;
  (y.*my_memfunc_ptr)(15, "Different parameters this time");

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

Указатель функции-члена можно установить в 0 и применять к нему операторы == и !=, но только для указателей членов-функций одного и того же класса. Любой указатель функции-члена можно сравнить с 0, чтобы проверить, не пустой ли он. [Это не работает во всех компиляторах. В Metrowerks MWCC указатель на первую виртуальную функцию простого класса будет равен нулю!] В отличие от простых указателей функций, сравнения на неравенство (<, >, <=, >=) для них недоступны. Как и указатели функций, они могут применяться в качестве нетипированных параметров шаблона, но это работает в малом числе компиляторов.