Функция Istream для чтения с параметром istream

Я пытаюсь понять этот код

istream &read(istream &is, Sales_data &item) 
{
    double price = 0;    
    is >> item.bookNo >> item.units_sold >> price;   
    item.revenue = price * item.units_sold;    
    return is;
} 

ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " "    
        << item.revenue << " " << item.avg_price();    
    return os; 
}

Я не понимаю, что это за функции, также я не могу понять, почему мы используем istream для чтения и ostream для печати вместо использования cin и cout.


person Stephen Gregory    schedule 17.02.2020    source источник
comment
Добро пожаловать в Stack Overflow! Вы можете пройти тур, чтобы ознакомиться с нашим сайтом.   -  person L. F.    schedule 17.02.2020


Ответы (2)


std::cin и std::cout являются конкретными экземплярами std::istream и std::ostream. Поэтому вы можете вызывать эти функции и передавать std::cin или std::cout в качестве потоков, которые хотите использовать. Это позволяет функциям быть более универсальными, потому что мы можем использовать потоки не только для ввода и вывода командной строки.

В частности, std::ifstream и std::ofstream для файлового ввода-вывода и std::istringstream и std::ostringstream для строкового ввода-вывода.

person JohnFilleau    schedule 17.02.2020
comment
мы можем использовать потоки не только для ввода и вывода командной строки, в частности, std::[i|o]fstream для файлового ввода-вывода и std::[i|o]stringstream для строкового ввода-вывода. - person L. F.; 17.02.2020
comment
Хорошее уточнение. Я украл его и добавил в свой ответ :) - person JohnFilleau; 17.02.2020

В игре есть несколько тонкостей, которые вам нужно понять, чтобы понять, что происходит в функциях 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
comment
Этот пример очень помог!!! Теперь для меня все более ясно. Благодарю вас! - person Stephen Gregory; 17.02.2020
comment
Таким образом, в основном этот параметр istream &is является ссылкой для cin. (cin и &is являются экземплярами istream) - person Stephen Gregory; 17.02.2020
comment
В яблочко. Вы передаете любой поток, из которого хотите read читать. В приведенном выше случае это был std::cin, с тем же успехом это мог быть и открытый файловый поток. Обычно вы видите, как это делается с перегруженными операторами << и >>, а не с написанием функции read и print, но любой из них подойдет. См. Не удается загрузить правильную информацию из файла для недавнего примера перегрузки << и >>. - person David C. Rankin; 17.02.2020