67370

Перевантаження операторів введення-виведення даних

Лекция

Информатика, кибернетика и программирование

У розглянутих раніше прикладах програм для виконання операції введення або виведення «класових» даних створювалися функції-члени класів, призначення яких полягало тільки у тому, щоб ввести або вивести ці дані. Незважаючи на те, що у такому вирішенні цих питань немає нічого неправильного, проте у мові...

Украинкский

2014-09-07

85.5 KB

10 чел.

Лекція № 27

Тема: Перевантаження операторів введення-виведення даних

План

  1.  Особливості механізмів перевантаження операторів введення-виведення даних
  2.  Створення перевантажених операторів виведення даних
  3.  Використання функцій-"друзів" класу для перевантаження операторів виведення даних
  4.  Створення перевантажених операторів введення даних
  5.  Порівняння С- і С++-систем введення-виведення

  1.  Особливості механізмів перевантаження операторів введення-виведення даних

    У розглянутих раніше прикладах програм для виконання операції введення або виведення "класових" даних створювалися функції-члени класів, призначення яких полягало тільки у тому, щоб ввести або вивести ці дані. Незважаючи на те, що у такому вирішенні цих питань немає нічого неправильного, проте у мові програмування C++ передбачено дещо вдаліший спосіб виконання операцій введення-виведення "класових" даних – шляхом перевизначення операторів введення-виведення "<<" і ">>".

    У мові C++ оператор "<<" називається оператором виведення або вставлення, оскільки він вставляє символи у потік. Аналогічно оператор ">>" називається оператором введення або вилучення, оскільки він вилучає символи з потоку.

    Як уже зазначалося вище, оператори введення-виведення вже перевантажені (у заголовку <iostream>) для того, щоби вони могли виконувати операції потокового введення або виведення даних будь-яких вбудованих С++-типів. У цьому підрозділі можна буде дізнатися про те, як визначити ці оператори для створення власних класів.

  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. Нижче наведено навчальну програму, у якій продемонстровано механізм використання перевантаженого оператора виведення даних.

Приклад. Демонстрація механізму реалізації перевантаженого оператора виведення даних

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

}

void main()

{

kooClass ObjA(1, 2, 3), ObjB(3, 4, 5), ObjC(5, 6, 7);

      // Перевизначений оператор виведення даних

cout << ObjA << ObjB << ObjC;

}

   Внаслідок виконання ця програма відображає на екрані такі результати:

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. Це обмежує перелік ситуацій, в яких її можна використовувати.

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

  1.  Використання функцій-"друзів" класу для перевантаження операторів виведення даних

    У попередній програмі операторну функцію виведення даних не було визначено як член класу kooClass. Насправді ні будь-яка операторна функція виведення даних, ні функція їх введення не можуть бути членами класу. Справа тут полягає ось в чому. Якщо операторна функція є членом класу, то лівий операнд (що опосередковано передається за допомогою показника this) повинен бути об'єктом класу, який генерує звернення до цієї операторної функції. І це змінити не можна.

    Проте при перевантаженні операторів виведення даних лівий операнд повинен бути потоком, а правий – об'єктом класу, дані якого підлягають виведенню. Отже, перевантажені оператори виведення даних не можуть бути функціями-членами класу.

   У зв'язку з тим, що операторні функції виведення даних не можуть бути членами класу, для якого вони визначаються, то виникає серйозне запитання: як перевантажений оператор виведення даних може отримати доступ до закритих членів класу? У попередній програмі  змінні x, y і z були визначені як відкриті, тому оператор виведення даних без перешкод міг отримати до них доступ. Водночас закриття даних – важлива частина ООП, отже, вимагати, щоб усі дані були відкритими, просто нелогічно.

    Проте існує просте вирішення цього питання – оператор виведення даних можна зробити "другом" класу. Якщо функція є "другом" деякого класу, то вона отримує легальний доступ до його private-даних. Оголошення "другом" класу операторної функції виведення даних продемонструємо на прикладі класу kooClass.

Приклад. Демонстрація механізму використання функцій-"друзів" класу для   

                  перевантаження оператора виведення даних

class kooClass

{

     public:   

             int x, y, z;

             kooClass(int a, int b, int c) { x = a; y = b; z = c; }

             friend ostream &operator<<(ostream &stream, kooClass obj);

};

     // Відображення тривимірних координат x, y, z

     // Перевизначений оператор виведення даних для класу kooClass

ostream &operator<<(ostream &stream, kooClass obj)

{

stream << obj.x << ", ";

stream << obj.y << ", ";

stream << obj.z << endl;

return stream;           // Повертає посилання на параметр stream

}

void main()

{

kooClass ObjA(1, 2, 3), ObjB(3, 4, 5), ObjC(5, 6, 7);

     // Перевантажений оператор виведення даних

cout << ObjA << ObjB << ObjC;

}

   Зверніть увагу на те, що змінні x, y і z у цій версії коду програми є закритими у класі kooClass, проте операторна функція виведення даних звертається до них безпосередньо. У наведеному прикладі якраз і виявляється велика перевага "друзів" класу: оголошуючи операторні функції введення та виведення даних "друзями" класу, для якого вони визначаються, ми тим самим підтримуємо механізм інкапсуляції об'єктно-орієнтованого програмування.

  1.  Створення перевантажених операторів введення даних

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

   

    // Прийняття тривимірних координат x, y, z

    // Перевантажений оператор введення даних для класу kooClass

istream &operator>>(istream &stream, kooClass &obj)

{

cout << "Введіть координати x, y і z: ";

    // Перевантажений оператор введення даних

stream >> obj.x >> obj.y >> obj.z;

return stream;    // Повертає посилання на параметр stream

}

    Перевантажений оператор введення даних повинен повертати посилання на об'єкт типу istream. Окрім цього, перший параметр повинен бути посиланням на об'єкт типу istream. Цей тип належить потоку, що вказується зліва від оператора ">>". Другий параметр є посиланням на об'єкт, який приймає значення, що вводяться. Оскільки другий параметр – посилання на об'єкт, то його можна модифікувати при введенні інформації.

    Загальний формат перевизначеного оператора введення даних має такий вигляд:

istream &operator>>(istream &stream, objectType &obj)

{

     // код операторної функції введення даних

turn stream;      // Повертає посилання на параметр stream

}

    Особливості використання операторних функцій введення та виведення даних для об'єктів типу kooClass продемонстровано в такому коді програми.

Приклад. Демонстрація механізму перевантаження операторів введення/виведення

                  потокової інформації

 

class kooClass

{

int x, y, z;          // Тривимірні координати

public:

kooClass(int a, int b, int c) { x = a; y = b; z = c; }

friend ostream &operator<<(ostream &stream, kooClass obj);

friend istream &operator>>(istream &stream, kooClass &obj);

};

   // Відображення тривимірних координат x, y, z

   // Перевизначений оператор виведення даних для класу kooClass

ostream &operator<<(ostream &stream, kooClass obj)

{

stream << obj.x << ", ";

stream << obj.y << ", ";

stream << obj.z << endl;

return stream;             // Повертає посилання на параметр stream

}

  // Прийняття тривимірних координат x, y, z

  // Перевизначений оператор введення даних для класу kooClass

istream &operator>>(istream &stream, kooClass &obj)

{

cout << "Введіть координати x, y і z: ";

                      // Перевизначений оператор введення даних

stream >> obj.x >> obj.y >> obj.z;

return stream;              // Повертає посилання на параметр stream

}

void main()

{

kooClass ObjA(1, 2, 3);

cout << ObjA;             // Перевизначений оператор виведення даних

cin >> ObjA;               // Перевизначений оператор введення даних

cout << ObjA;             // Перевизначений оператор виведення даних

}

  Ось як виглядає результат виконання цієї програми:

1, 2, 3

Введіть координати x, y і z: 5 6 7

5, 6, 7

   Подібно до операторних функцій виведення даних, операторні функції їх введення не можуть бути членами класу, для оброблення даних якого вони призначені. Вони можуть бути тільки "друзями" цього класу або просто незалежними операторними функціями. За винятком того, що операторна функція введення даних повертає посилання на об'єкт типу istream, тіло цієї функції може містити все те, що програміст вважає за потрібне у неї помістити. Але логічніше використовувати оператори введення все ж таки за прямим призначенням, тобто для виконання операцій введення даних.

  1.  Порівняння С- і С++-систем введення-виведення

    Як Вам уже відомо, попередниця мови програмування C++, мова С оснащена однією з найгнучкіших (серед структурованих мов) і водночас дуже могутньою системою введення-виведення. Однак виникає логічне запитання: чому ж тоді у мові програмування C++ визначається власна система введення-виведення, якщо в ній продубльовано велику частину того, що міститься у мові С (маємо на увазі потужний набір С-функцій введення-виведення)? Відповісти на це запитання неважко. Йдеться про те, що С-система введення-виведення не забезпечує ніякої підтримки для об'єктів, які визначає користувач. Наприклад, якщо створити таку структуру

struct myStruct     // Оголошення типу структури

{

     int count;

     char str[80];

     double balance;

}

то наявну у мові C систему введення-виведення неможливо налаштувати так, щоб вона могла виконувати операції введення-виведення даних безпосередньо над об'єктами типу myStruct. Але, оскільки центром ООП є саме об'єкти, то виникає потреба у тому, щоб у мові програмування C++ функціонувала така система введення-виведення, яку можна було б динамічно "навчати" поводженню з будь-якими об'єктами, що створюються програмістом. Саме тому для мови програмування C++ і було винайдено нову об'єктно-орієнтовану систему введення-виведення. Як уже зазначалося вище, С++-підхід до введення-виведення даних дає змогу перевизначати оператори "<<" і ">>" так, що вони можуть працювати з класами, які створюють програмісти.


 

А также другие работы, которые могут Вас заинтересовать

69761. Продуктивність файлових систем 87 KB
  Оптимізація продуктивності під час розробки файлових систем Розглянемо яким чином можна оптимізувати продуктивність файлової системи зміною структур даних і алгоритмів які в ній застосовують. У викладі використовуватимемо класичний приклад оптимізації традиційної...
69762. Введення-виведення у режимі користувача 63 KB
  Тут зупинимося на взаємодії підсистеми введення-виведення із процесами режиму користувача та на різних методах організації введення-виведення з режиму користувача. Синхронне введення-виведення У більшості випадків введення-виведення на рівні апаратного...
69763. Таймери і системний час 27.5 KB
  Таймери керують пристроями які передають у систему інформацію про час. Вони відстежують поточний час доби здійснюють облік витрат процесорного часу повідомляють процеси про події що відбуваються через певний проміжок часу тощо.
69764. Термінальне введення-виведення в UNIX та Linux 40.5 KB
  Консоль Linux емулює спеціальний вид термінала, який називають Linux. Він надає доволі широкі можливості щодо керування відображенням інформації (підтримку кольору, керуючих клавіш, перевизначення символьної таблиці «на ходу»).
69765. Графічний інтерфейс користувача 61.5 KB
  Спільним у них є набір основних елементів реалізації куди входять вікна з елементами керування кнопками смугами прокручування тощо меню і піктограми а також використання пристрою для переміщення курсору по екрану та вибору окремих елементів наприклад миші.
69766. Реалізація стека протоколів Інтернету 66 KB
  Канальний рівень (data link layer) відповідає за передавання кадру даних між будь-якими вузлами в мережах із типовою апаратною підтримкою (Ethernet, FDDI тощо) або між двома сусідніми вузлами у будь-яких мережах (SLIP, PPP).
69767. Завантаження операційної системи Linux 57.5 KB
  Під час завантаження Linux використовують двоетапний завантажувач. Є кілька програмних продуктів, що реалізують такі завантажувачі, найвідоміший із них l i l o (від Іішіх loader). Він може бути встановлений як у MBR (замінивши там код, що завантажує перший сектор активного розділу)...
69768. Завантаження Windows XP 40 KB
  Завантаження Windows XP починають стандартним способом — із передавання керування коду завантажувального сектора активного розділу диска. Головне його завдання — визначити місцезнаходження файла ntldr у кореневому каталозі цього розділу, завантажити його...
69769. Продуктивність багатопроцесорних систем 29 KB
  Під масштабуванням навантаження (workload scalability) у SMP-системах розуміють вплив додавання нових процесорів на продуктивність системи. У реальних умовах воно залежить від багатьох факторів.