
- •7. Робота з шаблонними, функціями та класами
- •7.1. Поняття про узагальнені функції
- •7.1.1. Механізм реалізації шаблонної функції з одним узагальненим типом
- •7.1.2. Безпосередньо задане перевизначення узагальненої функції
- •7.1.3. Шаблонна функція з двома узагальненими типами
- •7.1.4. Механізм перевизначення специфікації шаблону функції
- •7.1.5. Використання стандартних параметрів у шаблонних функціях
- •7.1.6. Обмеження, які застосовуються при використанні узагальнених функцій
- •7.1.7. Приклад створення узагальненої функції abs()
- •7.2. Поняття про узагальнені класи
- •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.4. Зчитування та записування у файл блоків даних
Для зчитування і записування у файл блоків двійкових даних використовуються функції-члени read() і write(). Їх прототипи мають такий вигляд:
istream &read(char *buf, streamsize num);
ostream &write(const char *buf, int streamsize num);
1. Функція read() зчитує num байт даних з пов'язаного з файлом потоку і поміщає їх у буфер, який адресується покажчиком buf.
2. Функція write() записує num байт даних у пов'язаний з файлом потік з буфера, який адресується покажчиком buf.
Як уже зазначалося вище, тип streamsize визначається як певний різновид цілочисельного типу. Він дає змогу зберігати найбільшу кількість байтів, яку можна передана у процесі будь-якої операції введення-виведення даних.
У процесі виконання наведеної нижче програми спочатку у файл записується масив цілих чисел, а потім його значення зчитується з файлу.
Демонстрація механізму використання функцій read() і write()
#include <iostream> // Для потокового введення-виведення
#include <fstream> // Для роботи з файлами
using namespace std; // Використання стандартного простору імен
int main()
{
int n[5] = {1, 2, 3, 4, 5};
register int i;
ofstream out("test", ios::out | ios::binary);
if(!out) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
out.write((char *) &n, sizeof n);
out.close();
for(i=0; i<5; i++) n[i] = 0; // Очищує масив
ifstream in("test", ios::in | ios::binary);
if(!in) {
cout << "Не вдається відкрити файл" << endl;
return 1;
}
in.read((char *) &n, sizeof n);
for(i=0; i<5; i++) // Відображаємо значення, зчитані з файлу.
cout << n[i] << " ";
in.close();
getch(); return 0;
}
Зверніть увагу на те, що в настановах звернення до функцій read() і write() виконуються операції приведення типу, які є обов'язковими при використанні буфера, що визначається у вигляді не символьного масиву.
Функція gсоипt () повертає кількість символів, зчитаних у процесі виконання останньої операцгі введення даних.
Якщо кінець файлу досягнуто ще до того моменту, як було зчитано num символів, то функція read() просто припинить своє виконання, а буфер міститиме стільки символів, скільки вдалося зчитати до цього моменту. Точну кількість зчитаних символів можна дізнатися за допомогою ще однієї функції-члена класу gcount(), яка має такий прототип:
streamsize gcount();
Функція gcount() повертає кількість символів, зчитаних у процесі виконання останньої операції введення даних.
10. Динамічна ідентифікація типів і оператори приведення типу
У цьому розділі розглянемо два засоби мови програмування C++, які підтримують сучасне ООП: динамічна ідентифікація типів (run-time type identification –RTTI) і набір додаткових операторів приведення типу. Жоден з цих засобів не був частиною оригінальної специфікації мови програмування C++, але обидва вони були додані у нову версію мови C++ з метою посилення підтримки поліморфізму тривалості виконання. Під RTTI розуміють можливість проведення ідентифікації типу об'єкта у процесі виконання програми. Оператори приведення типу, що розглядаються у цьому розділі, пропонують програмісту безпечніші способи виконання цієї операції. Як буде показано далі, один з них – dynamic_cast безпосередньо пов'язаний з RTTI-ідентифікацією, тому оператори приведення типу і RTTI є сенс розглядати в одному розділі.