Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.О.П / ооп / 4_кол / Лекції / ООП (16. Робота з потоками).doc
Скачиваний:
22
Добавлен:
30.05.2020
Размер:
240.13 Кб
Скачать

Лекція

Тема: Потоки в мові Си++

План:

  1. Що таке потоки введення-виводу і як вони використовуються

  2. Як за допомогою потоків управляти введенням і виведенням даних

  3. Як за допомогою потоків записувати інформацію у файл і потім прочитувати її

Знайомство з потоками

Мова програмування C++ спеціально не визначає, яким чином дані виводяться на екран або у файл або як вони прочитуються програмою. Проте ці особливості є важливою частиною роботи програміста, тому стандартна бібліотека C++ включає бібліотеку iostream, що спрощує уведення-виведення (I/O).

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

Інкапсуляція

Класи iostream розглядають інформацію, що виводиться програмою на екран, як побітовий потік даних. Якщо дані виводяться у файл або на екран, то джерело потоку, як правило, міститься в програмі. Якщо ж потік направлений в протилежну сторону, дані можуть поступати з клавіатури або файлу на диску. В цьому випадку вони заносяться в змінні.

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

Мал. 1. Інкапсуляція за допомогою потоків

Буферизація

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

Суть ідеї проілюстрована на прикладі знайомого з шкільної лави бака з водою (рис..2). Вода заливається зверху, і бак поступово наповнюється, оскільки нижній вентиль закритий.

Коли вода (дані) досягає верху, нижній вентиль автоматично відкривається і вся вода виливається (мал. 3).

Як тільки бак спустіє, нижній вентиль закривається, а верхній відкривається знов, і вода знову поступає в бак (мал. 4).

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

Мал. 2. Буфер наповнюється даними, як закритий бак — водою

Мал. 3. Відкривається зливний вентиль, і вода (дані) зливається з бака

Мал. 4. Повторне наповнення бака

Мал. 5. Очищення буфера подібне до екстреного зливу води

Потоки і буфери

У C++ застосовується об'єктно-орієнтований підхід до реалізації обміну даними з потоками, що буферизують.

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

• Клас ios є базовим для класів потоків введення-виводу. Як змінна-член класу ios виступає об'єкт streambuf.

• Класи istream і ostream є похідними від класу ios і відповідають відповідно за потокове введення і виведення даних.

• Клас iosteam є похідним від класів istream і ostream і забезпечує методи введення-виводу для друку на екран.

• Класи fstream використовуються для введення-виводу з файлів.

Стандартні об'єкти введення-виводу

При запуску програми, що включає класи iostreams, створюються і ініціюються чотири об'єкти.

Примітка: Бібліотека класу iostream вбудована в компілятор. Аби додати в свою програму методи цього класу, досить в перших рядках програми включити вираження #include<iostream>.

• Об'єкт cin (виголошується як "си-ин" від англійського "see-in") обробляє введення з клавіатури.

• Об'єкт cout (виголошується як "сі-аут" від англійського "see-out") обробляє вивід на екран.

• Об'єкт cerr (виголошується як "сі-ер" від англійського "see-err") обробляє виведення помилок, що не буферизує, на стандартний пристрій виведення повідомлень про помилки, тобто на екран. Оскільки вивід не буферизує, то всі дані, що направляються в сerr, відразу ж виводяться пристроєм виводу.

• Об'єкт clog (виголошується як "сі-балка" від англійського "see-log") обробляє повідомлення, що буферизують, про помилки, які виводяться на стандартний пристрій виведення повідомлень про помилки (екран). Частенько ці повідомлення переадресуються у файл реєстрації.

Переадресація

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

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

Пайпінгом називається використання виведення однієї програми як введення для іншої.

В цілому переадресація більше відноситься до функцій операційної системи, а не бібліотек iostream. Мова C++ надає доступ до чотирьох стандартних пристроїв і необхідний набір команд для переадресації пристроїв введення-виводу.

Виведення даних за допомогою cin

Глобальний об'єкт cin відповідає за введення даних і стає доступним при включенні в програму класу iostream. У попередніх прикладах використовується переобтяжений оператор введення (>>) для привласнення даних, що вводяться, змінним програми. Для введення даних використовується наступний синтаксис".

int someVariable;

cout << "Enter а number: ";

cin >> someVariable;

Інший глобальний об'єкт, cout, і його використання для виведення даних обговорюється декілька нижче. Зараз же зупинимося на третьому рядку:

cin >> someVariable;.

Що ж є об'єктом cin?

На глобальність цього об'єкту вказує той факт, що його не потрібно оголошувати в коді програми. Об'єкт cin включає переобтяженого оператора введення (>>), яке записує дані, що зберігаються в буфері cin, в локальну змінну someVariable. Причому оператор введення переобтяжений таким чином, що личить для введення даних всіх базових типів, включаючи int&, short&, long&, double&, float&, char&, char* і тому подібне

Використання cin показане в лістингу 1.

Лістинг 1. Використання cin для введення даних різних типів

1: //Листинг 1. Введення даннах за допомогою cin

2:

3: #include <iostream.h>

4:

5: int main()

6: {

7:    int myInt;

8:    long myLong;

9:    double myDouble;

10:   float myFloat;

11:   unsigned int myUnsigned;

12:

13:   cout << "int: ";

14:   cin >> myInt;

15:   cout << "Long: ";

16:   cin >> myLong;

17:   cout << "Double: ";

18:   cin >> myDouble;

19:   cout << "Float: ";

20:   cin >> myFloat;

21:   cout << "Unsigned: ";

22:   cin >> myUnsigned; 23:

24:   cout << "\n\nInt:\t" << myInt << endl;

25:   cout << "Long:\t" << myLong << endl;

26:   cout << "Double:\t" << myDouble << endl;

27:   cout << "Float:\t" << myFloat << endl;

28:   cout << "Unsigned:\t" <<myUnsigned << endl;

29:   return 0;

30: }

Результат:

int: 2

Long: 70000

Double: 987654321

Float: 3.33

Unsigned: 25

Int: 2

Long: 70000

Double: 9.87654e+08

Float: 3.33

Unsigned: 25

Аналіз: У рядках 7—11 оголошуються змінні різних типів. У рядках 13—22 користувачеві пропонується ввести значення для цих змінних, після чого результати виводяться в рядках 24—28 (за допомогою cin).

Інформація, що виводиться програмою, говорить про те, що змінні записуються і виводяться відповідно до їх типа.

Рядки

Об'єкт cin також може приймати як аргумент покажчик на рядок символів (char*), що дозволяє створювати буфер символів і заповнювати його за допомогою cin. Наприклад, можна написати наступне:

char YourName[50]

cout << "Enter your name: ";

cin >> YourName;

Якщо ввести ім'я Jesse, змінна YourName заповниться символами J, e, s, s, e і \0. Останнім буде кінцевий нульовий символ, оскільки cin автоматично вставляє його. Тому при визначенні розміру буфера потрібно поклопотатися про те, аби він був чималим і міг вміщати всі символи рядка, включаючи кінцевий нульовий символ.

Проблеми, що виникають при введенні рядків

Успішно виконавши всі описані раніше операції з об'єктом cin, ви будете неприємно здивовані, якщо спробуєте ввести в рядку повне ім'я. Річ у тому, що cin розглядає пропуск як заданий за умовчанням роздільник рядків. Після того, як в рядку виявляється пропуск, введення рядка завершується додаванням кінцевого нульового символу. Ця проблема показана в лістингу 2.

Лістинг 2. Спроба введення рядка з помощьм cin  

1: //Лістинг 2. Проблеми з введенням рядка з допомогою cin

2:

3: #include <iostream.h>

4:

5: int main()

6: {

7:    char YourName[50];

8:    cout << "Your first name: ";

9:    cin >> YourName;

10:   cout << "Here it is: " << YourName << endl;

11:   cout << "Your entire name: ";

12:   cin >> YourName;

13:   cout << "Here it is: " << YourName << endl;

14:   return 0;

15: }

Результат:

Your first name: Jesse

Here it is: Jesse

Your entire name: Jesse Liberty

Here it is: Jesse

Аналіз: Рядком 7 для зберігання рядка, що вводиться користувачем, створюється масив символів. У рядку 8 користувачеві пропонується ввести ім'я, і, як видно з виводу, це ім'я зберігається правильно.

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

Аби зрозуміти, чому cin працює саме так, проаналізуйте лістинг 3, в якому показаний приклад введення рядка значень.