Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

17.1. Поняття про узагальнені функції

Узагальнена функція визначає загальний набір операцій, які призначено для їх застосування до даних різних типів. Тип даних, що обробляється функцією, передається їй як параметр. Використовуючи узагальнену функцію для оброблення широкого діапазону даних, можна застосувати єдину загальну процедуру. Можливо, Вам відомо, що багато алгоритмів мають однакову логіку для різних типів даних. Наприклад, один і той самий алгоритм сортування Quicksort застосовується і до масиву цілих чисел, і до масиву значень з плинною крапкою. Відмінність тут полягає тільки в типі сортованих даних. Створюючи узагальнену функцію, можна визначити природу алгоритму незалежно від типу даних. Після цього компілятор автоматично згенерує коректний програмний код для типу даних, який насправді використовується у процесі виконання цієї функції. По суті, створюючи узагальнену функцію, Ви створюєте функцію, яка автоматично перевантажує себе саму.

Узагальнена функція – це функція, яка перевантажує сама себе.

Узагальнена функція створюється за допомогою ключового слова template. Звичайне значення слова "template" точно відображає мету його застосування у мові програмування C++. Це ключове слово використовують для створення шаблону (або оболонки), який описує дії, що виконуються функцією. Компіляторові ж залишається "доповнити відсутні деталі" відповідно до заданого значення параметра. Загальний формат визначення шаблонної функції має такий вигляд:

template <class Ttype> тип ім'я_функції (список_параметрів)

{

// тіло функції

}

Визначення узагальненої функції починається з ключового слова template.

У цьому записі елемент Ttype є "заповнювачем" для типу даних, що обробляються функцією. Це ім'я може бути використано в тілі функції. Але воно означає всього тільки заповнювач, замість якого компілятор автоматично підставить реальний тип даних під час створення конкретної версії функції. І хоча для задавання узагальненого типу в template-оголошенні за традицією застосовується ключове слово class, однак можна також використовувати ключове слово typename.

17.1.1. Шаблонна функція з одним узагальненим типом

У наведеному нижче прикладі створюється шаблонна функція з одним узагальненим типом, яка змінює місцями значення двох змінних, що використовується під час її виклику. Оскільки загальний процес обміну значеннями змінних не залежить від їх типу, він є прекрасним претендентом для створення узагальненої функції.

Код програми 17.0. Демонстрація механізму застосування шаблонної функції з одним узагальненим типом

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

// Визначення шаблонної функції.

template <class aType> void swapAB(aType &a_ob, aType &b_ob)

{

aType tmp; // Створення тимчасового об'єкта

tmp = a_ob;

a_ob = b_ob;

b_ob = tmp;

}

int main()

{

int i = 10, j = 20;

double x = 10.1, y = 23.3;

char a = 'x', b = 'z';

cout << "Початкові значення i, j: " << i << " " << j << "\n";

cout << "Початкові значення x, y: " << x << " " << y << "\n";

cout << "Початкові значення а, b: " << a << " " << b << "\n";

swapAB(i, j); // перестановка цілих чисел

swapAB(x, y); // перестановка чисел з плинною крапкою

swapAB(a, b); // перестановка символів

cout << "Після перестановки i, j: " << i << " " << j << "\n";

cout << "Після перестановки x, y: " << x << " " << y << "\n";

cout << "Після перестановки а, b: " << a << " " << b << "\n";

getch(); return 0;

}

Ось як виглядають результати виконання цієї програми:

Початкові значення i, j: 10 20

Початкові значення х, у: 10.1 23.3

Початкові значення а, b: x z

Після перестановки i, j: 20 10

Після перестановки х, у: 23.3 10.1

Після перестановки а, b: z x

Отже, розглянемо уважно код програми. Рядок

template <class aType> void swapAB(aType &a_ob, aType &b_ob)

повідомляє компілятор, по-перше, що створюється шаблон, і, по-друге, що тут починається узагальнене визначення. Позначення aType є узагальненим типом, який використовується як "заповнювач". За template-заголовком знаходиться оголошення функції swapAB(), у якому символ aType означає тип даних для значень, які мінятимуться місцями. У функції main() продемонстровано виклик функції swapAB() з використанням трьох різних типів даних: int, double і char. Оскільки функція swapAB() є узагальненою, то компілятор автоматично створює три версії функції swapAB(): одну для обміну цілих чисел, другу для обміну чисел з плинною крапкою і третю для обміну символів.

Тут необхідно уточнити деякі важливі терміни, пов'язані з шаблонами. По-перше, узагальнена функція (тобто функція, оголошення якої передує template-настанові) також називається шаблонною функцією. Обидва терміни використовуються у цьому навчальному посібнику як взаємозамінні. Коли компілятор створює конкретну версію цієї функції, то говорять, що створюється її спеціалізація (або конкретизація). Спеціалізація також називається породженою функцією (generated function). Дію породження функції визначають як її реалізацію (instan­tia­ting). Іншими словами, породжувана функція є конкретним примірником шаблонної функції.

Оскільки мова програмування C++ не розпізнає символ кінця рядка як ознаку кінця настанови, то template-частина визначення узагальненої функції може не знаходитися в одному рядку з іменем цієї функції. У наведеному нижче прикладі показано ще один (достатньо поширений) спосіб форматування функції swapAB():

template <class aType> void swapAB(aType &a_ob, aType &b_ob)

{

aType tmp; // Створення тимчасового об'єкта

tmp = a_ob;

a_ob = b_ob;

b_ob = tmp;

}

Під час використання цього формату важливо розуміти, що між template-настановою і початком визначення узагальненої функції ніякі інші настанови знаходитися не можуть. Наприклад, у наведеному нижче коді програми не скомпілюється:

// Цей програмний код не скомпілюється

template <class aType>

int i; // Тут помилка!

void swapAB(aType &a_ob, aType &b_ob)

{

aType tmp; // Створення тимчасового об'єкта

tmp = a_ob;

a_ob = b_ob;

b_ob = tmp;

}

Як зазначено в коментарі, template-специфікація повинна знаходитися безпосередньо перед визначенням функції. Між ними не може знаходитися ні настанова оголошення змінної, ні будь-яка інша настанова.