Операторы потоков
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 43 из 104.
Операторы вставки в поток (<<) и извлечения из потока (>>) позволяют использовать ваши пользовательские классы с std::cout и std::cin. В отличие от операторов, которые мы рассматривали до сих пор, они должны быть реализованы как функции, не являющиеся членами класса, поскольку левый операнд является потоком, а не вашим классом.
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
// Объявите как friend для доступа к закрытым членам
friend std::ostream& operator<<(std::ostream& os, const Point& p);
friend std::istream& operator>>(std::istream& is, Point& p);
};
std::ostream& operator<<(std::ostream& os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")";
return os;
}
std::istream& operator>>(std::istream& is, Point& p) {
is >> p.x >> p.y;
return is;
}Оба оператора возвращают ссылку на поток, что позволяет выстраивать цепочки, такие как std::cout << p1 << p2. Оператор вставки принимает объект по const ссылке, так как он только считывает данные, в то время как оператор извлечения принимает неконстантную ссылку, так как он изменяет объект.
Теперь вы можете использовать Point естественным образом с потоками:
Point p(3, 4);
std::cout << "Location: " << p << std::endl; // Вывод: Location: (3, 4)
Point p2(0, 0);
std::cin >> p2; // Чтение двух целых чисел в p2Задание
ЛегкоДавайте создадим класс Temperature, который можно будет легко использовать с std::cout и std::cin с помощью перегрузки операторов потока. Это практический сценарий, когда вы хотите отображать температуру в читаемом формате и считывать её из входных данных естественным образом.
Вы создадите два файла для организации своего кода:
Temperature.h: Определите классTemperature, который хранит значение в градусах Цельсия (какdouble) и метку единицы измерения (какchar, либо'C'для Цельсия, либо'F'для Фаренгейта). Ваш класс должен иметь:- Приватные члены для значения температуры и единицы измерения
- Конструктор по умолчанию, который инициализирует значение 0.0 градусов Цельсия
- Параметризованный конструктор, принимающий значение и единицу измерения
- Геттеры
getValue()иgetUnit()(оба const) - Дружественные объявления (friend) для операторов вставки в поток (
<<) и извлечения из потока (>>)
Реализуйте операторы потока как функции, не являющиеся членами класса:
- Оператор вставки должен выводить температуру в формате
VALUE UNIT(например,25.5 Cили77.9 F). Используйте один десятичный знак для значения. - Оператор извлечения должен считывать значение и символ единицы измерения из потока и сохранять их в объекте Temperature.
Оба оператора должны возвращать ссылку на поток для обеспечения возможности цепочки вызовов.
main.cpp: Считайте две температуры из входных данных. Каждая температура указывается в отдельной строке в форматеvalue unit(например,25.5 C).Создайте два объекта
Temperature, используя оператор извлечения для их чтения изstd::cin. Затем выведите их с помощью оператора вставки в следующем формате:Temperature 1: <temp1> Temperature 2: <temp2>Например, если входные данные:
25.5 C 98.6 FВыходные данные должны быть:
Temperature 1: 25.5 C Temperature 2: 98.6 F
Используйте std::fixed и std::setprecision(1) из <iomanip>, чтобы отформатировать значение температуры ровно с одним десятичным знаком. Не забудьте про include guards (защиту заголовков) в вашем заголовочном файле.
Шпаргалка
Операторы вставки в поток (<<) и извлечения из потока (>>) позволяют пользовательским классам работать с std::cout и std::cin. Эти операторы должны быть реализованы как функции, не являющиеся членами класса, так как левым операндом является объект потока, а не ваш класс.
Базовый синтаксис
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
// Объявите как friend для доступа к приватным членам
friend std::ostream& operator<<(std::ostream& os, const Point& p);
friend std::istream& operator>>(std::istream& is, Point& p);
};
std::ostream& operator<<(std::ostream& os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")";
return os;
}
std::istream& operator>>(std::istream& is, Point& p) {
is >> p.x >> p.y;
return is;
}Ключевые моменты
- Оба оператора возвращают ссылку на поток для обеспечения возможности цепочки вызовов (например,
std::cout << p1 << p2) - Оператор вставки (
<<) принимает объект по константной ссылке (constreference), так как он только считывает данные - Оператор извлечения (
>>) принимает неконстантную ссылку, так как он изменяет объект - Используйте объявления
friend, чтобы позволить этим функциям, не являющимся членами класса, обращаться к приватным членам
Пример использования
Point p(3, 4);
std::cout << "Location: " << p << std::endl; // Вывод: Location: (3, 4)
Point p2(0, 0);
std::cin >> p2; // Считывание двух целых чисел в p2Попробуйте сами
#include <iostream>
#include "Temperature.h"
int main() {
// TODO: Создайте два объекта Temperature
// TODO: Используйте оператор извлечения (>>) для чтения двух температур из std::cin
// TODO: Выведите температуры, используя оператор вставки (<<)
// Формат:
// Temperature 1: <temp1>
// Temperature 2: <temp2>
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер