В игре есть несколько тонкостей, которые вам нужно понять, чтобы понять, что происходит в функциях read
и print
. С точки зрения обзора istream
и ostream
— это общие классы ввода и вывода, которые обеспечивают основу для потокового ввода-вывода в C++. Как правильно указано в другом ответе и комментариях, std::cin
и std::cout
являются производными от istream
и ostream
для обеспечения ввода/вывода из стандартного потока stdin
и stdout
.
У самого потока есть состояние, которое определяет, является ли поток исправным и может ли он быть прочитан или записан, или произошла ли ошибка потока, препятствующая дальнейшему вводу-выводу (некоторые сбои можно восстановить, некоторые — нет). См. std::basic_ios::rdstate и std::basic_ios::setstate для обсуждения битов (goodbit, badbit, failbit, eofbit
), составляющих состояние потока.
Теперь посмотрим на ваши прототипы функций:
istream &read(istream &is, Sales_data &item)
а также
ostream &print(ostream &os, const Sales_data &item)
Заметили, что первый параметр является ссылкой на текущий поток? И обратите внимание, что return также является ссылкой на тот же самый поток? Это важно, потому что он передает ссылку на поток, поэтому любые изменения в состоянии Steam, происходящие внутри функции, будут доступны по возврату. Таким образом, если в функции read
встречается eof
, это изменение состояния будет доступно по возврату. То же самое для вашей функции print
(хотя потенциальных ошибок, которые могут изменить поток, меньше и они разные)
В read
вы читаете 3 части информации из потока, item.bookNo, item.units_sold
и price
, и обновляете item.revenue
:
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
Вы можете прочитать из std::cin
, передав его в качестве аргумента для is
, или вы можете передать открытый файловый поток. Потоковые операции будут работать для любого допустимого потока.
Функция печати делает обратное, она выводит результат item.isbn(), item.units_sold, item.revenue
и результат item.avg_price()
в качестве вывода. Если вы передадите std::cout
как os
Последняя команда в обеих функциях возвращает поток, включая любые изменения в состоянии потока, чтобы вызывающая сторона могла проверить, были ли read
или print
успешными. Это ключ к тому, чтобы вызывающая сторона могла определить, имел ли место ввод-вывод.
Слишком упрощенный пример
Чрезмерно упрощенный пример использования функции может помочь понять концепцию. Здесь мы объявляем упрощенную структуру Sales_data
с int bookno, units_sold;
и double price, revenue;
. Например:
#include <iostream>
struct Sales_data
{
int bookno, units_sold;
double price, revenue;
};
Затем мы упрощаем read
, чтобы читать только bookno, units_sold
и price
, и вычисляем revenue
для этого отдельного элемента, например.
std::istream &read(std::istream &is, Sales_data &item)
{
is >> item.bookno >> item.units_sold >> item.price;
item.revenue = item.price * item.units_sold;
return is;
}
И упростите print
, чтобы выводить только units_sold
и revenue
:
std::ostream &print(std::ostream &os, const Sales_data &item)
{
os << "units sold: " << item.units_sold << " revenue: $" << item.revenue << '\n';
return os;
}
Теперь вы можете очень просто увидеть, предлагая пользователю ввести bookno, units_sold
и price
, как работают функции read
и print
, а также как ошибка, возникающая в одной из функций, изменяет состояние потока. . Короткий main()
может быть:
int main (void) {
Sales_data sd;
std::cout << "enter bookno units_sold price: ";
if (read (std::cin, sd)) /* if read succeeds */
print (std::cout, sd); /* print data */
else
std::cerr << "error: invalid input\n";
}
Пример использования/вывода
$ ./bin/readprintstream
enter bookno units_sold price: 12 100 12.95
units sold: 100 revenue: $1295
или если возникает ошибка:
$ ./bin/readprintstream
enter bookno units_sold price: 23 banannas 12.28
error: invalid input
Надеюсь, обсуждение и пример помогут немного прояснить концепцию. Если у вас есть дополнительные вопросы, дайте мне знать.
person
David C. Rankin
schedule
17.02.2020