- •7. Робота з шаблонними, функціями та класами
- •7.1. Поняття про узагальнені функції
- •7.1.1. Механізм реалізації шаблонної функції з одним узагальненим типом
- •7.1.2. Безпосередньо задане перевизначення узагальненої функції
- •7.1.3. Шаблонна функція з двома узагальненими типами
- •7.1.4. Механізм перевизначення специфікації шаблону функції
- •7.1.5. Використання стандартних параметрів у шаблонних функціях
- •7.2. Поняття про узагальнені класи
- •7.1.6. Обмеження, які застосовуються при використанні узагальнених функцій
- •7.1.7. Приклад створення узагальненої функції abs()
- •7.2.1. Створення класу з одним узагальненим типом даних
- •7.2.2. Створення класу з двома узагальненими типами даних
- •7.2.3. Приклад створення узагальненого класу для організації безпечного масиву
- •7.2.4. Використання в узагальнених класах аргументів, що не є узагальненими типами
- •11.2.1. Передача покажчиком на функцію її адреси іншій функції
- •9.2.3. Класи потоків
- •9.3. Особливості механізмів перевизначення операторів введення-виведення даних
- •9.3.1. Створення перевизначених операторів виведення даних
- •9.5. Організація файлового введення-виведення даних
- •9.5.1. Відкриття та закриття файлу
- •9.5.2. Зчитування та запис текстових файлів
- •9.5.3. Неформатне введення-виведення даних у двійковому режимі
- •9.5.4. Зчитування та записування у файл блоків даних
- •10. Динамічна ідентифікація типів і оператори приведення типу
- •10.1. Динамічна ідентифікація типів
- •10.1.1. Отримання типу об'єкта у процесі виконання програми
- •10.1.2. Приклад rtti-застосування
- •11. Поняття про простори імен та інші ефективні програмні засоби
- •11.1. Особливості організації простору імен
- •11.1.1. Поняття про простори імен
- •11.1.2. Застосування настанови using
- •11.1.3. Неіменовані простори імен
- •11.1.4. Застосування простору імен std
- •11.2. Застосування покажчиків на функції
- •11.2.2. Пошук адреси перевизначеної функції
- •11.3. Поняття про статичні члени-даних класу
- •11.5. Застосування до функцій-членів класу модифікаторів const і mutable
- •11.6. Використання explicit-конструкторів
- •12. Введення в стандартну бібліотеку шаблонів
- •12.1. Огляд стандартної бібліотеки шаблонів
- •12.2. Поняття про контейнерні класи
- •12.3. Механізми роботи з векторами
- •12.3.1. Доступ до елементів вектора за допомогою ітератора
- •12.3.2. Вставлення та видалення елементів з вектора
- •12.3.3. Збереження у векторі об'єктів класу
- •12.3.4. Доцільність використання ітераторів
- •7. Робота з шаблонними, функціями та класами 1
- •7.1. Поняття про узагальнені функції 1
- •10. Динамічна ідентифікація типів і оператори приведення типу 26
- •11. Поняття про простори імен та інші ефективні програмні засоби 31
- •12. Введення в стандартну бібліотеку шаблонів 44
7.1.6. Обмеження, які застосовуються при використанні узагальнених функцій
Узагальнені функції подібні до перевизначених функцій, але мають більше обмежень з їх застосування. При перевизначенні функцій в тілі кожної з них зазвичай записують різні дії. Але узагальнена функція повинна виконувати одні і тісамі дії для всіх її версій; відмінність між версіями полягає тільки в типі оброблюваних даних. Розглянемо приклад, у якому перевизначені функції не можна замінити узагальненою функцією, оскільки вони виконують різні дії:
void outdata(int i)
{
cout << i << endl;
}
void outdata(double d)
{
cout << d * 3.1416 << endl;
}
7.1.7. Приклад створення узагальненої функції abs()
Давайте знову звернемося до функції abs(). Пригадайте, як у розд. 8 стандартні бібліотечні функції abs(), labs() і fabs() були згруповані в три перевизначені функції із загальним іменем myAbs(). Кожна з перевизначених версій функції myAbs() призначена для повернення абсолютного значення для даних "свого" типу. Незважаючи на те, що показане в розд. 8 [9] перевизначення функції abs() можна вважати кроком уперед порівняно з використанням трьох різних бібліотечних функцій (з різними іменами), все ж таки це не кращий механізм реалізації функції, яка повертає абсолютне значення заданого аргументу. Оскільки процедура повернення абсолютного значення числа однакова для всіх типів числових значень, то функція abs() може слугувати типовим прикладом для створення шаблонної функції. За наявності узагальненої версії функції abs() компілятор зможе автоматично створювати необхідну її версію. Програміст у цьому випадку звільняється від написання окремих версій для кожного типу даних1.
У наведеному нижче коді програми міститься узагальнена версія функції myAbs(). Неважко переконатися в тому, що узагальнена версія цієї функції є набагато коротшою і володіє більшою гнучкістю.
Демонстрація механізму створення узагальненої версії функції, яка повертає абсолютне значення числа
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
using namespace std; // Використання стандартного простору імен
template <class aType> aType myAbs(aType n)
{
return n < 0 ? -n : n;
}
int main()
{
cout << myAbs(-10) << endl; // Для типу int
cout << myAbs(-10.0) << endl; // Для типу double
cout << myAbs(-10L) << endl; // Для типу long
cout << myAbs(-10.0F) << endl; // Для типу float
getch(); return 0;
}
Для вправи було б непогано, якби Ви спробували знайти інші бібліотечні функції-претенденти для перероблення їх в узагальнені функції. Необхідно пам'ятати – головне тут те, що один і той самий алгоритм повинен застосовуватися до широкого діапазону типу даних.
7.2. Поняття про узагальнені класи
Окрім визначення узагальнених функцій, можна також визначити узагальнений клас. Для цього створюється клас, у якому визначаються всі використовувані ним алгоритми. При цьому реальний тип оброблюваних у ньому даних задається як параметр при побудові об'єктів цього класу.
Узагальнені класи особливо є корисними тоді, коли в них використовується логіка, яку можна узагальнити. Наприклад, алгоритми, які підтримують функціонування черги цілочисельних значень, також надаються і для підтримки символьних значень. Механізм, який забезпечує підтримку зв'язного списку поштових адрес, також годиться для підтримки зв'язного списку, призначеного для зберігання даних про запчастини до автомобілів. Після свого створення узагальнений клас виконує визначену програмістом операцію (наприклад, підтримку черги або зв'язного списку) для будь-якого типу даних. Компілятор автоматично згенерує коректний тип об'єкта на основі типу, який задається під час його створення.
Загальний формат оголошення узагальненого класу має такий вигляд:
template <class tType> class ім'я_класу {
// Тіло класу
};
У цьому записі елемент tType є "заповнювачем" для імені типу, який задається під час реалізації класу. У разі потреби можна визначити декілька узагальнених типів даних, використовуючи перелік елементів, розділених між собою комами.
Створивши узагальнений клас, можна створити його конкретний примірник, використовуючи такий загальний формат:
ім'я_класу <тип> ім'я_об'єкту;
У цьому записі елемент тип означає ім'я типу даних, які оброблятимуться примірником узагальненого класу. Функції-члени узагальненого класу автоматично є узагальненими. Тому програмісту не потрібно використовувати ключове слово template для безпосереднього визначення їх такими.
