Если данные прочитаны успешно, определяем переменную 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).