Анимация
JavaScript
|
Главная Библионтека Ниже приведен более полный пример - версия рассмотренной ранее программы с обычной функцией (см. с. 129), переработанная для использования объекта функции: stl/foreach2.cpp #1nclucle <1ostreai]i> linclude <vector> #include <algor1thm> using namespace std: Простой объект функции для вывода передаваемого аргумента class Printlnt { public: void operatorO (int elem) const ( cout « elem « : int mainO { vector<int> coll: Вставка элементов со значениями от 1 до 9 for (int i=l; 1<=9; ++i) { col 1.push back(1); Вывод всех элементов for each (coll.beginO. coll.endO. Интервал PrintlntO); Операция cout « endl: Класс Printlnt определяет объект, для которого вызывается оператор () с аргументом int. Выражение Printlnt() в следующей команде создает временный объект этого класса, передаваемый алгоритму for each() в качестве аргумента: for each (coll.beginO. coll.endO. PrintlntO): Алгоритм for each() определяется примерно так: namespace std { template <class Iterator, class Operation Operation for each (Iterator act. Iterator end. Operation op) while (act != end) { Пока не достигнут конец интервала op(*act); - вызвать орО для текущего элемента ++act: - переместить итератор к следующему ) элементу return op: Алгоритм for each() использует временный объект функции ор, чтобы для каждого элемента делать вызов op(*act). Если третий параметр является обычной функцией, она просто вызывается с аргументом *act. Если третий параметр является объектом функции, вызывается оператор () объекта функции ор с аргументом *act. Таким образом, в приведенной программе алгоритм for each() вызывает операторную функцию printint:;operator()(*act) На первый взгляд непонятно, зачем это нужно. Возникает ощущение, что объекты функций - конструкция странная, непонятная, а то и вовсе бессмысленная. Действительно, объекты функций усложняют программу. Но они способны на большее, чем функции, обладая рядом несомненных достоинств. О Объект функции - это шумная функция». Объекты, которые ведут себя как указатели, называются «умными указателями». По аналогии объекты, которые ведут себя как функции, можно назвать «умными функциями», поскольку их возможности не ограничиваются вызовом оператора (). Объекты функций могут представлять другие функции и иметь другие атрибуты, а это означает, что объекты функций обладают состоянием. Одна и та же функция, представленная объектом функции, в разные моменты времени может находиться в разных состояниях. У обычных функций такая возможность отсутствует. Из этого следует одно из достоинств объектов функций - возможность их инициализации на стадии выполнения перед вызовом/использованием. О Каждому объекту функции соответствует свой тип. Обычные функции обладают разными типами только при различиях в их сигнатурах. С другой стороны, объекты функций могут иметь разные тины даже при полном совпадении сигнатур. Это открывает новые возможности для унифицированного программирования с применением шаблонов, потому что функциональное поведение может передаваться как параметр шаблона. Например, это позволяет контейнерам разных типов использовать единственный объект функции в качестве критерия сортировки. Тем самым предотвращается возможное присваивание, слияние и сравнение коллекций, использующих разные критерии сортировки. Вы даже можете спроектировать иерархию объектов функций, например, для определения нескольких специализированных версий одного общего критерия. О Объекты функгщй обычно работают быстрее функций. Шаблоны обычно лучше оптимизируются, поскольку на стадии компиляции доступно больше информации. Следовательно, передача объекта функции вместо обычной функции часто повышает быстродействие программы. В оставшейся части этого подраздела приводятся несколько примеров, доказывающих, что объекты функций действительно «умнее» обычных функций. Дополнительные примеры и подробности приводятся в главе 8, полностью посвященной объектам функций. В частности, вы узнаете, насколько полезной бывает передача функционального поведения в качестве параметра шаблона. for each(coll .beginO. coll.endO. Интервал addlO): Операция Если возможны разные приращения, известные па стадии компиляции, функция оформляется в виде шаблона: template <int theValuG> void add (int& elem) elem +- theValue; void flO { vector<int> coll: for Gach(coll.beg1n(). coll.endO. Интервал add<10>); Операция Ho если приращение определяется только во время выполнения программы, ситуация усложняется. Значение должно быть передано функции перед ее вызовом. Обычно в таких случаях применяется глобальная переменная, используемая как функцией, вызывающей алгоритм, так и функцией, вызываемой алгоритмом для суммирования. Программа получается неряшливой и запутанной. Если функция вызывается дважды с двумя разными приращениями, оба из которых становятся известными только во время выполнения, такая задача в принципе не решается одной обычной функцией. Прхтходится либо передавать функции дополнительный признак, либо писать две разные функции. Вам когда-нибудь приходилось копировать определение функции, потому что ее состояние хранилось в статической переменной, а вам требовалась та же функция, но с другим состоянием? Наша проблема в точности аналогична этой. Допустим, требуется увеличить значения всех элементов коллекции на некоторую величину. Если приращение иэвесттю на стадии компиляции, можно воспользоваться обычной функцией: void addlO (int& olem) elem += 10: void no vector<lnt> coll; 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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |