Урок №141. Перевантаження операторів вводу і виводу

  Юрій  | 

  Оновл. 16 Лют 2021  | 

 15

На цьому уроці ми розглянемо перевантаження операторів вводу і виводу в мові C++.

Перевантаження оператора виводу <<

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

Якщо ви захочете вивести об’єкт цього класу на екран, то вам потрібно буде зробити щось на кшталт наступного:

Звичайно, було б простіше написати окрему функцію для виводу, яку можна було б повторно використовувати. Наприклад, функцію print():

Тепер вже набагато краще, але тут також є свої нюанси. Оскільки метод print() типу void, то його не можна викликати всередині стейтменту виводу. Замість цього стейтмент виводу доведеться розбити на кілька частин (рядків):

А ось якби ми могли просто написати:

І отримати той же результат, але без необхідності розбивати стейтмент виводу на кілька рядків і пам’ятати ім’я функції виводу. На щастя, це можна зробити, перевантаживши оператор виводу <<.

Перевантаження оператора виводу << аналогічне перевантаженню оператора + (обидва є бінарними операторами), за винятком того, що їх типи різні.

Розглянемо вираз std::cout << point. Якщо оператором є <<, то чим тоді є операнди? Лівим операндом є об’єкт std::cout, а правим — об’єкт нашого класу Point. std::cout фактично є об’єктом типу std::ostream, тому перевантаження оператора << виглядає наступним чином:

Реалізація перевантаження оператора << для нашого класу Point досить-таки проста, так як C++ вже знає, як виводити значення типу double, а всі наші змінні-члени мають тип double, тому ми можемо просто використовувати оператор << для виводу змінних-членів нашого Point. Ось вищенаведений клас Point, але вже з перевантаженим оператором <<:

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

Найцікавіше тут — тип повернення. З перевантаженням арифметичних операторів ми вираховували і повертали результат по значенню. Однак, якщо ви спробуєте повернути std::ostream по значенню, то отримаєте помилку компілятора. Це станеться через те, що std::ostream забороняє своє копіювання.

В цьому випадку ми повертаємо лівий параметр в якості посилання. Це не тільки запобігає створенню копії std::ostream, але також дозволяє нам «зв’язати» стейтменти виводу разом, наприклад, std::cout << point << std::endl;.

Ви могли б подумати, що, оскільки оператор << не повертає значення назад в caller, то ми повинні були б вказати тип повернення void. Але подумайте, що відбудеться, якщо наш оператор << повертатиме void. Коли компілятор обробляє std::cout << point << std::endl;, то, враховуючи правила пріоритету/асоціативності, він оброблятиме цей вираз як (std::cout << point) << std::endl;. Тоді std::cout << point призведе до виклику функції перевантаження оператора <<, яка поверне void, і друга частина виразу оброблятиметься як void << std::endl; — в цьому немає сенсу!

Повертаючи параметр out в якості значення, що повертається, виразу (std::cout << point) ми повертаємо std::cout, і друга частина нашого виразу обробляється як std::cout << std::endl; — ось де сила!

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

Результат виконання програми:

Point(3, 4.7, 5) Point(9, 10.5, 11)

Перевантаження оператора вводу >>

Також можна перевантажити і оператор вводу. Все майже так само, як і з оператором виводу, але головне, що потрібно пам’ятати — std::cin є об’єктом типу std::istream. Ось наш клас Point з перевантаженим оператором вводу >>:

Ось приклад програми з використанням як перевантаженого оператора <<, так і оператора >>:

Припустимо, що користувач введе 4.0, 5.5 і 8.37, тоді результат виконання програми:

You entered: Point(4, 5.5, 8.37)

Висновки

Перевантаження операторів << і >> набагато спрощує процес виводу класу на екран і отримання користувацького вводу із записом в клас.

Тест

Використовуючи клас Fraction, представлений нижче, додайте перевантаження операторів << і >>.

Наступний фрагмент коду:

Повинен видавати наступний результат:

Enter fraction 1: 3/4
Enter fraction 2: 4/9
3/4 * 4/9 is 1/3

Ось клас Fraction:

Відповідь

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (Немає Оцінок)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *