Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

8.4.3 Передача операций как параметров функций

      Можно не задавать функцию сравнения как часть типа       Vector, а передавать ее как второй параметр функции sort().       Этот параметр является объектом класса, в котором определена       реализация операции сравнения:       template<class T> void sort(Vector<T>& v, Comparator<T>& cmp)       {       unsigned n = v.size();       for (int i = 0; i<n-1; i++)       for ( int j = n-1; i<j; j--)       if (cmp.lessthan(v[j],v[j-1])) {       // меняем местами v[j] и v[j-1]       T temp = v[j];       v[j] = v[j-1];       v[j-1] = temp;       }       }       Этот вариант можно рассматривать как обобщение традиционного приема,       когда операция сравнения передается как указатель на функцию.       Воспользоваться этим можно так:       void f(Vector<int>& vi,       Vector<String>& vc,       Vector<int>& vi2,       Vector<char*>& vs)       {       Comparator<int> ci;       Comparator<char*> cs;       Comparator<String> cc;       sort(vi,ci); // sort(Vector<int>&);       sort(vc,cc); // sort(Vector<String>&);       sort(vi2,ci); // sort(Vector<int>&);       sort(vs,cs); // sort(Vector<char*>&);       }       Отметим, что включение в шаблон класса Comparator как параметра       гарантирует, что функция lessthan будет реализовываться подстановкой.       В частности, это полезно, если в шаблонной функции используется       несколько функций, а не одна операция сравнения, и особенно это       полезно, когда эти функции зависят от хранящихся в том же объекте       данных.

8.4.4 Неявная передача операций

      В примере из предыдущего раздела объекты Comparator на самом деле       никак не использовались в вычислениях. Это просто "искусственные"       параметры, нужные для правильного контроля типов. Введение таких       параметров достаточно общий и полезный прием, хотя и не слишком       красивый. Однако, если объект используется только для передачи       операции (как и было в нашем случае), т.е. в вызываемой функции       не используется ни значение, ни адрес объекта, то можно вместо этого       передавать операцию неявно:       template<class T> void sort(Vector<T>& v)       {       unsigned n = v.size();       for (int i=0; i<n-1; i++)       for (int j=n-1; i<j; j--)       if (Comparator<T>::lessthan(v[j],v[j-1])) {       // меняем местами v[j] и v[j-1]       T temp = v[j];       v[j] = v[j-1];       v[j-1] = temp;       }       }       В результате мы приходим к первоначальному варианту использования       sort():       void f(Vector<int>& vi,       Vector<String>& vc,       Vector<int>& vi2,       Vector<char*>& vs)       {       sort(vi); // sort(Vector<int>&);       sort(vc); // sort(Vector<String>&);       sort(vi2); // sort(Vector<int>&);       sort(vs); // sort(Vector<char*>&);       }       Основное преимущество этого варианта, как и двух предыдущих, по       сравнению с исходным вариантом в том, что часть программы, занятая       собственно сортировкой, отделена от частей, в которых находятся       такие операции, работающие с элементами, как, например lessthan.       Необходимость подобного разделения растет с ростом программы, и       особенный интерес это разделение представляет при проектировании       библиотек. Здесь создатель библиотеки не может знать типы параметров       шаблона, а пользователи не знают (или не хотят знать) специфику       используемых в шаблоне алгоритмов. В частности, если бы в функции       sort() использовался более сложный, оптимизированный и рассчитанный       на коммерческое применение алгоритм, пользователь не очень бы       стремился написать свою особую версию для типа char*, как это было       сделано в $$8.4.1. Хотя реализация класса Comparator для специального       случая char* тривиальна и может использоваться и в других ситуациях.