Шаргин Александр
Шрифт:
Для реализации необходимого набора операторов используются вспомогательные методы Add, Remove, RemoveAll и Invoke. Метод Add добавляет новый указатель IDelegateVoid* в список:
Метод Remove ищет в списке делегат, ссылающийся на заданную функцию, и в случае обнаружения удаляет его:
Метод RemoveAll просто очищает список, удаляя из него все делегаты:
Наконец, метод Invoke вызывает все функции и методы, на которые ссылаются делегаты из списка:
Использовать полученный класс делегата можно примерно так.
Как видим, класс CDelegateVoid очень похож на делегаты из C#. Он полностью типобезопасен, так как попытка передать функции NewDelegate ссылку на функцию или метод, сигнатура которых отличается от void(void), немедленно приведёт к ошибке. Реализация класса CDelegateVoid не использует никаких предположений о размере и устройстве указателя на метод класса, поэтому он может использоваться как при обычном, так и при множественном и виртуальном наследовании. Его можно без изменений переносить на новые платформы и компиляторы.
Общая реализация
Теперь посмотрим, как можно обобщить класс CDelegateVoid для применения с различными сигнатурами. Используя шаблоны, мы можем параметризовать как тип возвращаемого значения, так и типы параметров функций, на которые ссылаются делегаты. В то же время, мы не можем определить единый шаблон, поддерживающий разное количество параметров, поэтому для каждого количества параметров необходимо реализовать свой класс. Поскольку наборы от 0 до 10 параметров покрывают 99% практических нужд при работе с делегатами, нам нужно написать 11 шаблонов делегатов CDelegate0, CDelegate1,…, CDelegate10. Вот как будет начинаться описание делегата, который возвращает произвольное значение и принимает произвольный (но ровно 1) параметр.