- •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.5.2. Зчитування та запис текстових файлів
Найпростіше зчитувати дані з текстового файлу або записувати їх до нього за допомогою операторів "<<" і ">>". Наприклад, у наведеному нижче коді програми здійснюється спочатку запис у файл test цілого числа, потім значення з плинною крапкою і на завершення текстового рядка.
Демонстрація механізму запису даних у файл
#include <iostream> // Для потокового введення-виведення
#include <fstream> // Для роботи з файлами
using namespace std; // Використання стандартного простору імен
int main()
{
ofstream out("test");
if(!out) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
out << 10 << " " << 123.23 << endl;
out << "Це короткий текстовий файл.";
out.close();
getch(); return 0;
}
Наведений нижче код програми зчитує ціле число, float-значення, символ і рядок з файлу, створеного у процесі виконання попередньою програмою:
Демонстрація механізму зчитування даних з файлу
#include <iostream> // Для потокового введення-виведення
#include <fstream> // Для роботи з файлами
using namespace std; // Використання стандартного простору імен
int main()
{
char ch;
int c;
float f;
char str[80];
ifstream in("test");
if(!in) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
in >> c;
in >> f;
in >> ch;
in >> str;
cout << c << " " << f << " " << ch << endl;
cout << str;
in.close();
getch(); return 0;
}
Варто пам'ятати! При використанні перевизначеного оператора ">>" для зчитування даних з текстових файлів відбувається перетворення деяких символів. Наприклад, "пропускні" символи опускаються. Якщо необхідно запобігти будь-яким перетворенням символів, то потрібно відкрити файл у двійковому режимі доступу до його даних.
Необхідно пам'ятати! При використанні перевизначеного оператора "»" для зчитування рядка введення даних припиняється внаслідок виявлення першого "пропускного" символу.
9.5.3. Неформатне введення-виведення даних у двійковому режимі
Форматні текстові файли (подібні до тих, які використовувалися у попередніх прикладах) корисні в багатьох ситуаціях, але вони не мають гнучкості неформатних двійкових файлів. Тому мова програмування C++ підтримує ряд функцій файлового введення-виведення у двійковому режимі, які можуть виконувати операції без форматування даних.
Для виконання двійкових операцій файлового введення-виведення необхідно відкрити файл з використанням специфікатора режиму ios::binary. Необхідно відзначити, що функції, які використовуються для оброблення неформатних файлів, можуть також виконувати дії з файлами, відкритими в текстовому режимі доступу, але при цьому використовується перетворення символів, яке зводить нанівець основну мету виконання двійкових файлових операцій.
Функція get() знищує символ з файлу, а функція put() записує символ у файл.
У загальному випадку існує два способи запису неформатних двійкових даних у файл і зчитування їх з файлу. Перший спосіб полягає у використанні функції-члена класу put() (для запису байта у файл) і функції-члена класу get() (для зчитування байта з файлу). Другий спосіб передбачає застосування "блокових" С++-функцій введення-виведення read() і write(). Розглянемо кожен спосіб окремо.
Функції get() і put() мають багато форматів, але найчастіше використовуються такі їх версії:
istream &get(char &ch);
ostream &put(char ch);
1. Функція get() зчитує один символ з відповідного потоку і поміщає його значення у змінну ch. Вона повертає посилання на потік, що пов'язаний із заздалегідь відкритим файлом. Досягнувши кінця цього файлу, значення посилання дорівнюватиме нулю.
2. Функція put() записує символ ch у потік і повертає посилання на цей потік.
У процесі виконання наведеної нижче програми на екран буде виведено вміст будь-якого заданого файлу. Тут використовується функція get().
Демонстрація механізму відображення вмісту файлу за допомогою функції get()
#include <iostream> // Для потокового введення-виведення
#include <fstream> // Для роботи з файлами
using namespace std; // Використання стандартного простору імен
int main(int argc, char *argv[])
{
char ch;
if(argc !=2) {
cout << "Застосування: ім'я_програми <ім'я_файлу>" << endl;
return 1;
}
ifstream in(argv[1], ios::in | ios::binary);
if(!in) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
while(in) { // Досягши кінця файлу потоковий об'єкт in прийме значення false.
in.get(ch);
if(in) cout << ch;
}
in.close();
getch(); return 0;
}
Досягши кінця файлу, потоковий об'єкт in прийме значення ФАЛЬШ, яке зупинить виконання циклу while. Проте існує дещо коротший варіант коду програми організації циклу, призначеного для зчитування і відображення вмісту файлу:
while(in.get(ch)) cout << ch;
Цей варіант організації циклу також має право на існування, оскільки функція get() повертає потоковий об'єкт in, який, досягши кінця файлу, прийме значення false. У наведеному нижче коді програми для запису рядка у файл використовується функція put().
Демонстрація механізму використання функції put() для запису рядка у файл
#include <iostream> // Для потокового введення-виведення
#include <fstream> // Для роботи з файлами
using namespace std; // Використання стандартного простору імен
int main()
{
char *p = "Всім привіт!";
ofstream out("test", ios::out | ios::binary);
if(!out) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
while(*p) out.put(*p++);
out.close();
getch(); return 0;
}
