Если данные прочитаны успешно, определяем переменную trans для хранения всех транзакций. Условие цикла while также проверяет поток, возвращенный функцией read(). Пока операции ввода в функции read() успешны, условие выполняется и обрабатывается следующая транзакция.
В цикле while происходит вызов функции-члена isbn() объектов total и trans, возвращающей их ISBN. Если объекты total и trans относятся к той же книге, происходит вызов функции combine(), добавляющей компоненты объекта trans к текущей сумме, хранящейся в объекте total. Если объект trans представляет новую книгу, происходит вызов функции print(), выводящей итог по предыдущей книге. Поскольку функция print() возвращает ссылку на свой потоковый параметр, ее результат можно использовать как левый операнд оператора <<. Это сделано для того, чтобы вывести символ новой строки после результата, созданного функцией print(). Затем объект trans присваивается объекту total, начиная таким образом обработку записи следующей книги в файле.
По исчерпании ввода следует не забыть вывести данные последней транзакции. Для этого после цикла while используется еще один вызов функции print().
Упражнение 7.1. Напишите версию программы обработки транзакций из раздела 1.6 с использованием класса Sales_data, созданного для упражнений в разделе 2.6.1.
Sales_data
У пересмотренного класса будут те же переменные-члены, что и у версии, определенной в разделе 2.6.1: член типа string по имени bookNo, представляющий ISBN, член типа unsigned по имени units_sold, представляющий количество проданных экземпляров книги, и член типа double по имени revenue, представляющий общий доход от этих продаж.
Как уже упоминалось, у класса будут также две функции-члена, combine() и isbn(). Кроме того, предоставим классу Sales_data другую функцию-член, чтобы возвращать среднюю цену, по которой были проданы книги. Эта функция, назовем ее avg_price(), не предназначена для общего использования. Она будет частью реализации, а не интерфейса.
Функции-члены определяют (см. раздел 6.1) и объявляют (см. раздел 6.1.2) как обычные функции. Функции-члены add(), read() и print(), объявляются и определяются вне класса.
С учетом вышеизложенного напишем пересмотренную версию класса Sales_data:
struct Sales_data {
//
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
//
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);
Хотя каждый член класса должен быть объявлен в самом классе, тело функции-члена можно определить либо в, либо вне тела класса. Функция isbn() определяется в классе Sales_data, а функции combine() и avg_price() вне его.
Сначала рассмотрим функцию isbn(), возвращающую строку и имеющую пустой список параметров:
std::string isbn() const { return bookNo; }
Как и у любой функции, тело функции-члена является блоком. В данном случае блок содержит один оператор return, возвращающий значение переменной-члена bookNo объекта класса Sales_data. Интересно, как эта функция получает объект, член bookNo которого следует выбрать?
thisДавайте снова рассмотрим вызов функции-члена isbn():
total.isbn()
Здесь для вызова функции-члена isbn() объекта total используется точечный оператор (см. раздел 4.6).