- •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
9.3. Особливості механізмів перевизначення операторів введення-виведення даних
У розглянутих раніше прикладах програм для виконання операції введення або виведення "класових" даних створювалися функції-члени класів, призначення яких полягало тільки у тому, щоб ввести або вивести ці дані. Незважаючи на те, що у такому вирішенні цих питань немає нічого неправильного, проте у мові програмування C++ передбачено дещо вдаліший спосіб виконання операцій введення-виведення "класових" даних – шляхом перевизначення операторів введеннявиведення "<<" і ">>". У мові C++ оператор "<<" називається оператором виведення або вставлення, оскільки він вставляє символи у потік. Аналогічно оператор ">>" називається оператором введення або вилучення, оскільки він вилучає символи з потоку. Як уже зазначалося вище, оператори введення-виведення вже перевизначені (у заголовку <iostream>) для того, щоби вони могли виконувати операції потокового введення або виведення даних будь-яких вбудованих С++-типів. У цьому підрозділі можна буде дізнатися про те, як визначити ці оператори для створення власних класів.
9.3.1. Створення перевизначених операторів виведення даних
Як простий приклад розглянемо механізм створення оператора виведення даних для уже відомої нам з попередніх розділів (див. поч. у розд. 4.1) такої версії класу kooClass:
class kooClass { // Оголошення класового типу
public:
int x, y, z; // Тривимірні координати
kooClass(int a, int b, int c) { x = a; y = b; z = c; }
};
Щоб створити операторну функцію виведення даних для об'єктів типу kooClass, необхідно перевизначити оператор виведення даних "<<". Один з можливих способів його реалізації має такий вигляд:
// Відображення тривимірних координат x, y, z
// Перевизначений оператор виведення даних для класу kooClass
ostream &operator<<(ostream &stream, kooClass obj)
{
stream << obj.x << ", ";
stream << obj.y << ", ";
stream << obj.z << endl;
return stream; // Повертає посилання на параметр stream
}
Розглянемо уважно цю операторну функцію, оскільки її вміст характерний для багатьох операторних функцій виведення даних. По-перше, зверніть увагу на те, що, згідно з оголошенням, вона повертає посилання на об'єкт типу ostream. Це дає змогу декілька звичайних операторів виведення даних об'єднати в одному складеному виразі. По-друге, зверніть увагу також на те, що ця функція має два параметри. Перший є посиланням на потік, який використовується в лівій частині оператора "<<". Другим є об'єкт, який знаходиться у правій частині цього оператора(У разі потреби другий параметр також може мати тип посилання на об'єкт). Саме тіло операторної функції складається з настанов виведення трьох значень координат, що містяться в об'єкті типу kooClass, і настанови повернення потоку stream. Нижче наведено навчальну програму, у якій продемонстровано механізм використання перевизначеного оператора виведення даних.
Демонстрація механізму реалізації перевизначеного оператора виведення даних
#include <iostream> // Для потокового введення-виведення
using namespace std; // Використання стандартного простору імен
class kooClass { // Оголошення класового типу
public:
int x, y, z; // Тривимірні координати
kooClass(int a, int b, int c) { x = a; y = b; z = c; }
};
// Відображення тривимірних координат x, y, z
// Перевизначений оператор виведення даних для класу kooClass
ostream &operator<<(ostream &stream, kooClass obj)
{
stream << obj.x << ", ";
stream << obj.y << ", ";
stream << obj.z << endl;
return stream; // Повертає посилання на параметр stream
}
int main()
{
kooClass ObjA(1, 2, 3), ObjB(3, 4, 5), ObjC(5, 6, 7);
// Перевизначений оператор виведення даних
cout << ObjA << ObjB << ObjC;
getch(); return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати:
1, 2, 3
3, 4, 5
5, 6, 7
Якщо видалити програмний код, який стосується звичайних операторів виведення даних конкретного класу kooClass, то залишиться "скелет", що відповідає будь-якій операторній функції виведення даних:
ostream &operator<<(ostream &stream, class_type obj)
{
// Код операторної функції виведення даних
return stream; // Повертає посилання на параметр stream
}
Як було уже наголошено вище, для параметра obj дозволяється використовувати посилання для його передачі.
Загалом конкретні дії, які має виконувати операторна функція виведення даних, визначає програміст. Але, якщо у Вас виникає бажання дотримуватися професійного стилю програмування, то створена програмістом операторна функція виведення даних повинна тільки виводити інформацію. Проте, завжди не зайве впевнитися в тому, що вона повертає тільки параметр stream.
Перш ніж переходити до наступного розділу, подумайте, чому операторна функція виведення даних для класу kooClass не була запрограмована так:
// Версія обмеженого застосування (використанню не підлягає).
ostream &operator<<(ostream &stream, kooClass obj)
{
cout << obj.x << ", ";
cout << obj.y << ", ";
cout << obj.z << endl;
return stream; // Повертає посилання на параметр stream
}
Не важко здогадатися, що у такій версії операторної функції жорстко закодований потік cout. Це обмежує перелік ситуацій, в яких її можна використовувати.
Необхідно пам'ятати! Перевизначений оператор "<<" можна застосовувати для виведення будь-якого потоку. Потік даних, який використовується у "<<"-виразі, передається параметруу stream.
Отже, програміст повинен передавати операторній функції виведення даних потік, який коректно працює в усіх конкретних випадках. Тільки так можна створити досконалу операторну функцію виведення даних, яка підійде для використання в будь-яких виразах введення-виведення.
