Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lektsii_OOP.doc
Скачиваний:
4
Добавлен:
01.03.2025
Размер:
4 Mб
Скачать

11. Функции- и классы-шаблоны

11.1 Функции-шаблоны (родовые функции)

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

Определение имеет формат

template <class X[, class Y,…]> имя_функции

{определение_функции}

Причем вместо типа какого-либо аргумента (или всех) или возвращаемого значения может стоять X, Y,…, где X, Y,… – идентификаторы для обозначения произвольного типа данных.

Рассмотрим такую задачу: отсортировать массив целых чисел и строк методом пузырька.

Вообще говоря, потребовалось бы создать 2 функции для сортировки каждого массива и 2 для обмена двух значений, т.е. 4 функции. Вместо этого напишем 2 функции-шаблона. Определим дополнительно еще 2 функции шаблона – для нахождения max элемента в массиве данных и вывода на экран двух значений данных разного типа.

enum boolean {FALSE, TRUE};

#include "string.hpp"

#include "complex.hpp"

template <class T> inline void Swap(T & a, T & b)

{T c;

c = a, a = b, b = c;

}

template <class T> T Max(T * a, int n)

{int i;T max = a[0];

for(i = 1; i < n; i++)

if (a[i] > max) max = a[i];

return max;

}

template <class T> void Bul_bul(T * a, int n) // улучшенный «пузырек» с флагом f

{int i, j, f;

for(i = 0, f = 1; i < n – 1 && f; i++)

for(j = f = 0; j < n – i – 1; j++)

if (a[j] > a[j + 1]) {Swap(a[j], a[j + 1]); f = 1;}

}

template <class X, class Y> void out2(X a, Y b)

{cout << a << ' ' << b; }

Как же будет работать компилятор?

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

void main()

{ Complex b[5] = {Complex(4, 2), Complex(-3, 4), 1, -2};

String s[5] = {"Петров", "Сибирякова", "Горцев", "Савин", "Буторина"};

int a[10] = {5, 3, 9, 6, 2, 0, 1152, 7, 4}, i;

cout << "\n Мax среди строк " << Max(s, 5); // Генерируется экземпляр String Max(String*, int)

cout << "\n Мax среди целых чисел " << Max(a, 9); // Генерируется экземпляр int Max(int *, int)

Bul_bul(s, 5); // Генерируется экземпляр void Bul_bul(String *, int );

cout << "\nОтсортированные строки ";

for(i = 0; i < 5; i++)

out2(s[i], ' '); // генерируется экземпляр void out2(String , char );

Bul_bul(a, 9); // генерируется экземпляр void Bul_bul(int *, int);

cout << "\nОтсортированные целые числа\n";

for(i = 0; i < 9; i++)

out2(a[i], ' '); // генерируется экземпляр void out2(int , char );

cout << "\nКомплексные числа\n";

for(i = 0; i < 5; i++)

out2(b[i], " "); // генерируется экземпляр void out2(Complex, char *)

out2(endl, "*********"); // генерируется экземпляр void out2(char, char *)

getch();

}

При порождении экземпляров функции-шаблона сортировки Bul_bul(...) компилятор сгенерирует также 2 функции Swap –

Swap (String &, String &) и Swap(int &, int &).

Программа будет работать при выполнении следующих условий:

  1. в классе String должна быть перегружена операции сравнения на > ;

  2. в классах String и Complex должна быть перегружена операция потокового вывода <<;

  3. в классе String, кроме того, должна быть перегружена операция =.

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

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