//
//
std::multiset
items{compare};
Это объявление может быть трудно понять, но, читая его слева направо, можно заметить, что определяется контейнер multiset
указателей shared_ptr
на объекты класса Quote
. Для упорядочивания элементов контейнер multiset
будет использовать функцию с тем же типом, что и функция-член compare()
. Элементами контейнера multiset
будут объекты items
, которые инициализируются для использования функции compare()
.
Basket
Класс Basket
определяет только две функции. Функция-член add_item()
определена в классе. Она получает указатель shared_ptr
на динамически созданный объект класса Quote
и помещает его в контейнер multiset
. Вторая функция-член, total_receipt()
, выводит полученный счет для содержимого корзины и возвращает цену за все элементы в ней:
double Basket::total_receipt(ostream &os) const {
double sum = 0.0; //
//
//
//
for (auto iter = items.cbegin();
iter != items.cend();
iter = items.upper_bound(*iter)) {
//
//
//
sum += print_total(os, **iter, items.count(*iter));
}
os << "Total Sale: " << sum << endl; //
return sum;
}
Цикл for
начинается с определения и инициализации итератора iter
на первый элемент контейнера multiset
. Условие проверяет, не равен ли iter
значению items.cend()
. Если да, то обработаны все покупки и цикл for
завершается. В противном случае обрабатывается следующая книга.
Интересный момент — выражение "инкремента" в цикле for
. Это не обычный цикл, читающий каждый элемент и перемещающий итератор iter
на следующий. При вызове функции upper_bound()
(см. раздел 11.3.5) он перескакивает через все элементы, которые соответствуют текущему ключу. Вызов функции upper_bound()
возвращает итератор на элемент сразу после последнего с тем же ключом, что и iter
. Возвращаемый итератор обозначает или конец набора, или следующую книгу.
Для вывода подробностей по каждой книге в корзине в цикле for
происходит вызов функции print_total()
(см. раздел 15.1):
sum += print_total(os, **iter, items.count(*iter));
Аргументами функции print_total()
являются поток ostream
для записи, обрабатываемый объект Quote
и счет. При обращении к значению итератора iter
возвращается указатель shared_ptr
, указывающий на объект, который предстоит вывести. Чтобы получить этот объект, следует обратиться к значению этого указателя shared_ptr
. Таким образом, выражение **iter
возвращает объект класса Quote
(или класса производного от него). Для выяснения количества элементов в контейнере multiset
с тем же ключом (т.е. с тем же ISBN) используется его функция-член count()
(см. раздел 11.3.5).
Как уже упоминалось, функция print_total()
осуществляет вызов виртуальной функции net_price()
, поэтому полученная цена зависит от динамического типа **iter
. Функция print_total()
выводит общую сумму для данной книги и возвращает вычисленную общую стоимость. Результат добавляется в переменную sum, которая выводится после завершения цикла for
.
Пользователи класса Basket
все еще должны иметь дело с динамической памятью, поскольку функция add_item()
получает указатель shared_ptr
. В результате пользователи вынуждены писать код так:
Basket bsk;
bsk.add_item(make_shared
("123", 45));
bsk.add_item(make_shared