头文件.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;
}
}