头文件.h
#ifndef BASKET_H #define BASKET_H #include <iostream> #include <string> #include <set> #include <map> #include <utility> #include <cstddef> #include <stdexcept> // Item sold at an undiscounted price // derived classes will define various discount strategies class Item_base { friend std::istream& operator>>(std::istream&, Item_base&); friend std::ostream& operator<<(std::ostream&, const Item_base&); public: //都定义了clone函数来返回一个自身的副本,在句柄类初始化时,会用得到它们 virtual Item_base* clone() const { return new Item_base(*this); } public: //构造函数 Item_base(const std::string &book = "", double sales_price = 0.0): isbn(book), price(sales_price) { } //返回ISBN号 std::string book() const { return isbn; } // returns total sales price for a specified number of items // derived classes will override and apply different discount algorithms //基类不需要折扣 virtual double net_price(std::size_t n) const { return n * price; } // no work, but virtual destructor needed // if base pointer that points to a derived object is ever deleted virtual ~Item_base() { } private: std::string isbn; // identifier for the item protected: double price; // normal, undiscounted price }; class Sales_item; bool compare(const Sales_item &lhs, const Sales_item &rhs); // discount kicks in when a specified number of copies of same book are sold // the discount is expressed as a fraction used to reduce the normal price //保存折扣率和购买数量的类 //它有两个派生类,实现两种折扣模式 //只要超过了预定的数量就都有折扣。 class Bulk_item : public Item_base { public: //卖多少书和折扣率绑定 std::pair<size_t, double> discount_policy() const { return std::make_pair(min_qty, discount); } // other members as before Bulk_item* clone() const { return new Bulk_item(*this); } //两个构造函数 Bulk_item(): min_qty(0), discount(0.0) { } Bulk_item(const std::string& book, double sales_price, std::size_t qty = 0, double disc_rate = 0.0): Item_base(book, sales_price), min_qty(qty), discount(disc_rate) { } // redefines base version so as to implement bulk purchase discount policy //重定义折扣价钱 double net_price(std::size_t) const; private: std::size_t min_qty; // minimum purchase for discount to apply享受折扣最少买的书 double discount; // fractional discount to apply折扣率 }; // discount (a fraction off list) for only a specified number of copies, // additional copies sold at standard price //超出部分才有折扣 class Lim_item : public Item_base { public: Lim_item(const std::string& book = "", double sales_price = 0.0, std::size_t qty = 0, double disc_rate = 0.0): Item_base(book, sales_price), max_qty(qty), discount(disc_rate) { } // redefines base version so as to implement<实现> limited discount policy《折扣政策》 double net_price(std::size_t) const; private: std::size_t max_qty; // maximum number sold at discount最大折扣 double discount; // fractional discount to apply折扣分数 public: Lim_item* clone() const { return new Lim_item(*this); } std::pair<size_t, double> discount_policy() const { return std::make_pair(max_qty, discount); } }; // use counted handle class for the Item_base hierarchy 《继承层次结构》 //定义一个句柄类里管理这个继承层次中的基类或者派生类对象: class Sales_item { friend class Basket; public: // default constructor: unbound handle //默认构造函数,不与任何对象关联,初始化指针为0 和 计数器为1 Sales_item(): p(0), use(new std::size_t(1)) { } // attaches a handle to a copy of the Item_base object Sales_item(const Item_base&); // copy control members to manage the use count and pointers Sales_item(const Sales_item &i): p(i.p), use(i.use) { ++*use; } ~Sales_item() { decr_use(); } Sales_item& operator=(const Sales_item&); // member access operators const Item_base *operator->() const { if (p) return p; else throw std::logic_error("unbound Sales_item"); } const Item_base &operator*() const { if (p) return *p; else throw std::logic_error("unbound Sales_item"); } private: Item_base *p; // pointer to shared item绑定到Item_base //执行Item_base的操作。 //指向基类的指针,也可以用来指向派生类 std::size_t *use; // pointer to shared use count //指向引用计数 // called by both destructor and assignment operator to free pointers void decr_use() { if (--*use == 0) { delete p; delete use; } } }; // holds items being purchased class Basket { // type of the comparison function used to order the multiset typedef bool (*Comp)(const Sales_item&, const Sales_item&); public: // make it easier to type the type of our set typedef std::multiset<Sales_item, Comp> set_type; // typedefs modeled after corresponding container types typedef set_type::size_type size_type; typedef set_type::const_iterator const_iter; void display(std::ostream&) const; // workaround MS compiler bug: must explicitly pass function address //默认构造函数,将比较函数确定为compare Basket(): items(&compare) { } // initialze the comparator //容器内添加对象 void add_item(const Sales_item &item) { items.insert(item); } //交易次数 size_type size(const Sales_item &i) const { return items.count(i); } //所欲的交易的钱数 double total() const; // sum of net prices for all items in the basket private: std::multiset<Sales_item, Comp> items; }; inline Sales_item::Sales_item(const Item_base &item): p(item.clone()), use(new std::size_t(1)) { } // compare defines item ordering for the multiset in Basket inline bool compare(const Sales_item &lhs, const Sales_item &rhs) { return lhs->book() < rhs->book(); } #endif
源文件cpp
#include "Basket.h" #include <algorithm> using std::multiset; using std::map; using std::pair; using std::size_t; using std::string; using std::ostream; using std::endl; using std::min; using std::cout; // debugging routine to check contents in a Basket void Basket::display(ostream &os) const { os << "Basket size: " << items.size() << endl; // print each distinct isbn in the Basket along with // count of how many copies are ordered and what their price will be // upper_bound returns an iterator to the next item in the set for (const_iter next_item = items.begin(); next_item != items.end(); next_item = items.upper_bound(*next_item)) { // we know there's at least one element with this key in the Basket os << (*next_item)->book() << " occurs " << items.count(*next_item) << " times" << " for a price of " << (*next_item)->net_price(items.count(*next_item)) << endl; } } void print_total(ostream &, const Item_base&, size_t); // calculate and print price for given number of copies, applying any discounts void print_total(ostream &os, const Item_base &item, size_t n) { os << "ISBN: " << item.book() // calls Item_base::book << "\tnumber sold: " << n << "\ttotal price: " // virtual call: which version of net_price to call is resolved at run time << item.net_price(n) << endl; } double Basket::total() const { double sum = 0.0; // holds the running total //首先是循环的遍历并不是使用iter++来完成的,而是使用iter = items.upper_bound(*iter)。对于multiset,upper_bound返回的是指向某一个键的最后一个元素的下一个位置,这样就可以一次处理同一本书。当然,这里的有一个前提,就是对于同一本书,它的折扣策略、折扣率以及达到折扣所满足的数量是一致的。 for (const_iter iter = items.begin(); iter != items.end(); iter = items.upper_bound(*iter)) //iter解引获得的是Sales_item对象,利用定义的箭头操作符可以访问基类或者派生类的net_price函数,这个函数的派生类版本需要一个表明有多少本书才打折的实参,这个实参通过调用关联容器的count调用获得。 //(*iter)表示一个键值 { // we know there's at least one element with this key in the Basket print_total(cout, *(iter->p), items.count(*iter));//count(*iter)几本书 // virtual call to net_price applies appropriate discounts, if any sum += (*iter)->net_price(items.count(*iter));//count是相同的键值的个数作为参数 } return sum; } // use-counted assignment operator; use is a pointer to a shared use count Sales_item& Sales_item::operator=(const Sales_item &rhs) { //引用计数+1 ++*rhs.use; //删除原来的指针 decr_use(); //将指针指向右操作数 p = rhs.p; //复制右操作数的引用计数 use = rhs.use; //返回左操作数的引用 return *this; } // if specified number of items are purchased, use discounted price double Bulk_item::net_price(size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; } // use discounted price for up to a specified number of items // additional items priced at normal, undiscounted price double Lim_item::net_price(size_t cnt) const { size_t discounted = min(cnt, max_qty); size_t undiscounted = cnt - discounted; return discounted * (1 - discount) * price + undiscounted * price; }s) { return lhs->book() < rhs->book(); }
main函数
#include "Basket.h" #include <iostream> using std::cout; using std::endl; int main() { Sales_item item1(Item_base("123", 45)); Sales_item item2(Bulk_item("345", 45, 3, .15)); Sales_item item3(Bulk_item("678", 55, 5, .25)); Sales_item item4(Lim_item("abc", 35, 2, .10)); Sales_item item5(Item_base("def", 35)); Basket sale; sale.add_item(item1); cout << "added first item" << endl; sale.add_item(item1); sale.add_item(item2); sale.add_item(item2); sale.add_item(item2); sale.add_item(item2); sale.add_item(item2); sale.add_item(item1); sale.add_item(item1); sale.add_item(item2); sale.add_item(item2); sale.add_item(item2); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item3); sale.add_item(item4); sale.add_item(item4); sale.add_item(item4); sale.add_item(item4); sale.add_item(item4); sale.add_item(item4); sale.add_item(item5); sale.add_item(item5); cout << "added last item" << endl; sale.display(cout); cout << sale.total() << endl; { // arguments are the isbn, price, minimum quantity, and discount Bulk_item bulk("0-201-82470-1", 50, 5, .19); Basket sale; sale.add_item(Bulk_item("0-201-82470-1", 50, 5, .19)); sale.add_item(Bulk_item("0-201-82470-1", 50, 5, .19)); sale.add_item(Bulk_item("0-201-82470-1", 50, 5, .19)); sale.add_item(Bulk_item("0-201-82470-1", 50, 5, .19)); sale.add_item(Bulk_item("0-201-82470-1", 50, 5, .19)); sale.add_item(Lim_item("0-201-54848-8", 35, 2, .10)); sale.add_item(Lim_item("0-201-54848-8", 35, 2, .10)); sale.add_item(Lim_item("0-201-54848-8", 35, 2, .10)); double total = sale.total(); cout << "Total Sale: " << total << endl; } }