// набор multiset содержит несколько стратегий расценок,

// упорядоченных по сравниваемому элементу

std::multiset, decltype(compare)*>

 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; // содержит текущую сумму

 // iter ссылается на первый элемент в пакете элементов с тем же ISBN

 // upper_bound() возвращает итератор на элемент сразу после

 // конца этого пакета

 for (auto iter = items.cbegin();

      iter != items.cend();

      iter = items.upper_bound(*iter)) {

  // известно, что в Basket есть по крайней мере один элемент

  // с этим ключом

  // вывести строку для элемента этой книги

  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("345", 45, 3, .15));

Перейти на страницу:

Похожие книги