Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cpp_Страуструп.doc
Скачиваний:
18
Добавлен:
03.05.2015
Размер:
3.2 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* тривиальна и может использоваться и в других ситуациях.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]