Анимация
JavaScript
|
Главная Библионтека ции, не связанной с набором. Здесь в действие вступает сцепление, реализованное в классе Functor. По мере того как пользователь вводит все новые и новые символы, создаются все новые и новые функторы. Таким образом, возникает возможность выполнить последовательность нажатий клавиш как одну операцию. Функция-член Document: :lnsertchar, по существу, заталкивает функтор в стек отката. Когда пользователь выбирает пункт меню Undo, этот функтор должен быть выполнен и затолкнут в стек повтора операций. Как видим, связывание аргументов и сцепление позволяют нам работать с функторами единообразно: вид вызова не имеет значения, поскольку он скрыт внутри функтора. Это значительно облегчает задачу реализации операций отката и повтора операций. 5.15. Резюме Использовать хорошие библиотеки на языке С++ намного легче, чем создавать. С другой стороны, разрабатывать библиотеки очень интересно. Оглядываясь на детали описанных выше реализаций, можно извлечь несколько уроков, касающихся создания обобщенных профамм. • Создавайте гибкие шаблонные типы. Сфемитесь на все смофеть с максимально общей точки зрения. Классы FunctorHandl ег и MemFunHandl ег приобрели много преимуществ, благодаря тому, что в них используются шаблоны. Указатели на функции предоставляют большую свободу. По сравнению с их функциональными возможностями получающийся код имеет удивительно небольшой размер. Все эти выгоды достигаются благодаря использованию шаблонов и тому, что компилятору предоставлено право самому выводить типы, когда это возможно. • Обобщенное профаммирование способствует созданию семантики первого класса (см. примечание в начале главы. - Прим. ред.). Было бы крайне зафуднительно оперировать исключительно указателями на класс Functorlmpl. Представьте себе, как в этих условиях реализуются связывание и сцепление. Изощренные технологии предназначены для достижения большей простоты. На основе всех этих шаблонов, наследования, связывания и управления памятью создана простая, легкая в применении и хорошо продуманная библиотека. В двух словах, класс Functor задерживает вызов функции, функтора или функции-члена. Он сохраняет вызываемый объект и предоставляет для его вызова оператор О. Ниже приведено краткое описание этого класса. 5.16. Краткое описание класса Functor Класс Functor является шаблонным и позволяет выражать вызовы функций, имеющих до 15 аргументов. Первым шаблонным парамефом является тип возвращаемого значения, вторым - список типов, содержащий типы парамефов функции. Третий шаблонный парамеф задает потоковую модель, которая используется механизмом распределения памяти, применяемым в классе Functor. Подробная информация о списках классов приведена в главе 3, о потоковой модели - в приложении, о механизме распределения памяти для небольших объектов - в главе 4. • Объект класса Functor можно инициализировать функцией, функтором, другим объектом класса Functor или указателем на объект и указателем на метод, как показано в приведенном ниже примере. void Function(int) struct SomeFunctor void operatorOCint); truct SomeClass void MemberFunction(int); void exampleО инициализируем класс Functor функцией Functor<void, TYPELlST l(int)> cmdl(Function); инициализируем класс Functor функтором SomeFunctor fn; Functor<void, TYPELlST l(int)> cmd2(fn); инициализируем класс Functor указателем на объект и указателем на функцию-член SomeClass myobject; Functor<void, TYPELlST l(int)> cmd3(&myObject, &SomeClass:rMemberFunction); инициализируем класс Functor другим объектом класса Functor (копирование) Functor<void, TYPELlST l(int)> cmd4(cmd3); • Объект класса Functor можно инициализировать объектом класса std::auto ptr< Functorimpl<r, TList> >. Это позволяет создавать расширения, определенные пользователем. • Класс Functor поддерживает автоматические преобразования типов аргументов и возвращаемых значений. Например, в предыдущем примере функции-члены SomeFunctor::operatorO и SomeClass::MemberFunction могут получать аргументы типа double вместо аргументов типа int. • При перегрузке функций-членов следует создавать дополнительный код для устранения неоднозначности. • Класс Functor полностью поддерживает семантику первого класса: копирование, присваивание и передачу по значению. Класс Functor не является ни полиморфным, ни базовым. Если нужно расширить класс Functor, в качестве базового следует применять класс Functorlmpl. • Класс Functor поддерживает связывание аргументов. Вызов шаблонной функции BindFirst связывает первый аргумент с фиксированным значением. В результате возникает параметризованный класс Functor, параметрами которого являются остальные аргументы. Рассмотрим пример. void f() определяем класс Functor с тремя аргументами Functor<void, TYPELiST 3(int, int, double)> cmdl( someEntity); Связываем первый аргумент с числом 10 Functor<void, TYPELlST 2(int, double)> cmd2( BindFirst(cmdl, 10); Эквивалентно вызову cmdlClO, 20, 5.6) cmd2C20, 5.6) • Используя функцию chain, в одном объекте класса Functor можно сцепить несколько объектов этого класса. void fO { Functoro cmdlCsomething); Functoro cmd2CsomethingElse); Сцепливаем объекты cmdl и cmd2 в контейнер Functoro cmd3(chain(cmdl, cmd2)); Эквивалентно cmdlQ; cmd2C); ctndBQ; • Затраты, связанные с использованием простых объектов класса Functor, состоят из одной переадресации (вызова через указатель). При каждом связывании или сцепливании возникает один дополнительный виртуальный вызов. Параметры копируются только при необходимости преобразования типов. • Шаблонный класс Functorlmpl использует механизм распределения памяти для небольших объектов, описанный в главе 4. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 [ 44 ] 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |