Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга C++.doc
Скачиваний:
24
Добавлен:
10.11.2019
Размер:
2.48 Mб
Скачать

Домашнее задание

  1. Написать функцию, которая осуществляет поиск заданного слова в файлах по указанному пути и выводит на экран имена всех файлов, содержащих искомый элемент. Регистр букв не учитывать.

  2. Даны два входных файла с числовыми данными file1 и file2. Сформируйте выходной файл, содержащий все элементы из файла file1 и те элементы файла file2, которые отсутсвуют в первом файле.

    • а) используйте потоковый ввод/вывод

    • б) используйте функции языка Си.

Определение шаблонов функций

С помощью шаблонов функций языка С++ можно создать единственное общее определение функции, использующееся с различными типами данных.

Давайте вспомним тему "Перегруженные функции". Для использования одной и той же функции с различными типами данных нужно определить отдельную перегруженную версию этой функции для каждого типа. Если требуется функция, возвращающая абсолютную величину значения как типа int, так и типа double, то нужно написать две перегруженные функции. Например:

int Abs(int N)

{

return N < 0 ? -N : N;

}

double Abs(double N)

{

return N < 0. ? -N : N;

}

Используя шаблон языка С++, можно создать единственное определение, которое будет автоматически обрабатывать значения типа int, double или любого подходящего другого типа. Такой шаблон выглядит следующим образом:

template <class T> T Abs (T N)

{

return N < 0 ? -N : N;

}

В этом определении идентификатор T является параметром типа. Он определяет тип переменной или константы, передаваемой при вызове функции. Если программа вызывает функцию Abs и передает ей значения типа int, например,

cout << "Абсолютное значение для -5 = " << Abs(-5);

то компилятор автоматически создаст версию функции, в которой идентификатор T имеет тип int, и добавит в программу вызов данной версии функции.

Созданная компилятором функция будет эквивалентна функции, определенной явно:

int Abs (int N)

{

return N < 0 ? -N : N;

}

Аналогично, если программа вызывает функцию Abs и передает ей значение типа double, например,

double D = -5.12;

cout << "Абсолютное значение для D = " << Abs(D);

то компилятор автоматически сгенерирует версию функции, в которой заменит параметр типа T на double, и добавит в программу вызов данной версии функции. Эта версия функции эквивалентна следующей:

double Abs(double N)

{

return N < 0. ? -N : N;

}

Таким же образом компилятор создает дополнительные версии функции для каждого вызова, в котором указывается новый числовой тип данных, например, short или float. Генерация новой версии функции называется созданием экземпляра шаблона функции.

При определении шаблона нужно использовать спецификаторы template и class вместе с угловыми скобками, как показано в приведенном выше примере. Для параметра типа Т можно использовать любой корректный идентификатор имени, а в угловые скобки можно включать несколько параметров типа.

При определении шаблона функции не путатйте понятия параметр функции и параметр типа. Параметр функции - это значение, передаваемое в функцию при выполнении программы. Параметр типа, напротив, задает тип аргумента, передаваемого в функцию, и полностью обрабатывается при компиляции. Обратите внимание: в определении шаблона спецификатор class в угловых скобках ссылается на любой тип данных, фактически передаваемых при вызове (как встроенный, так и определенный программистом).

Само по себе определение шаблона не вызывает генерацию кода компилятором. Компилятор создает код функции только при ее фактическом вызове. Первый же вызов с определенным типом данных приводит к генерации компилятором кода соответствующей версии функции. Последующие вызовы с указанием тех же типов данных не сгенерируют дополнительные копии функции, а только вызовут ее первоначальную копию. Но компилятор создаст новую версию функции, если тип параметра не совпадает в точности с типом в предыдущем вызове. Например, рассмотрим случай, когда программа передает в шаблон функции параметр типа long, а компилятор генерирует соответствующую версию функции. Если затем программа передаст параметр типа int, компилятор создаст полностью новую версию функции для обработки типа int. Он не будет выполнять стандартное преобразование int в long для использования кода первой версии функции.

Еще один пример шаблона функции:

template <class T> T Max (T A, T B)

{

return A > B ? A : B;

}

Этот шаблон генерирует функции, возвращающие большее из двух значений одинакового типа. Так как оба параметра определены как имеющие тип идентификатора T, в вызове функции оба передаваемых переметра должны быть только одного типа. Иначе компилятор не определит, какой тип соответствует параметру T - тип первого или второго параметра. Таким образом допустимы такие вызовы функции:

cout << "Большее из 10 и 5 = " << Max(10, 5) << endl;

cout << "Большее из 'A' и 'B' = " << Max('A', 'B') << endl;

cout << "Большее из 3.5 и 5.1 = " << Max(3.5, 5.1) << endl;

А следующий вызов является недопустимым:

cout << "Большее из 10 и 5.55 = " << Max(10, 5.55); // ОШИБКА!

Компилятор не преобразует второй параметр int в double для приведения типов, хотя это преобразование является стандартным.

Чтобы передавать параметры различных типов, нужно определить шаблон функции.

template <class T1, class T2> T1 Max(T1 A , T2 B)

{

return T2 (A > B ? A : B);

}

В этом шаблоне Т1 обозначает тип значения, передаваемого в качестве первого параметра, а Т2 - второго.

Для такой версии шаблона следующий оператор допустим и печатает значение 5.55

cout << "Большее из 10 и 5.55 = " << Max(10, 5.55);

В С++ параметр типа можно использовать в любом месте кода, в котором используется имя типа.

Так как возвращаемое значение преобразуется к типу второго параметра, то при изменении порядка параметров предыдущего примера

cout << "Большее из 5.55 и 10 = " << Max(5.55, 10);

результат сравнения будет округлен и равняться 5.

Каждый параметр типа, встречающийся внутри символов "<" и ">", должен также появляться в списке параметров функции. Т.е. следующее определение шаблона функции недопустимо:

template <class T1, class T2> T1 Max(T1 A , T1 B)

{

return A > B ? A : B;

}

// ОШИБКА! список параметров должен включать T2 как параметр типа.

При таком определении компилятор, встретив вызов функции, не сможет определить значение идентификатора T2. Это - ошибка, даже если идентификатор T2 не использован.