《C++ Primer》 书店程序

对于《算法导论》第一部分 C++综合实现《算法导论》第六章 堆排序 C++实现的补充:
最近复习《C++ Primer》,注意到一个重要的东西,位于第三章“标准库类型”:关键概念:安全的泛型编程

1
2
for (vector<int>::size_type ix = 0; ix != ivec.size(); ++ix)
ivec[ix] = 0;

1. c++程序猿习惯于优先选用!=而不是<来编写判断条件。
2. 有些数据结构(如vector)可以动态增长,所以在for中调用size成员函数,而不是在进入循环前,存储size值的副本。
于是,之前两篇里的代码大部分循环就都不太符合规范了。如:

1
for (elemIndex = 0; elemIndex <= heapSize; ++elemIndex)

最好写成

1
for (elemIndex = 0; elemIndex != heapSize - 1; ++elemIndex)

(在堆排序中,heapSize 是堆的元素数,而不是容器中总的元素数,所以不能写成 elemIndex != elemQueue.size())

由于只是复习,这程序的代码大部分书上都有,边复习同时就整理了出来,包括习题的实现,所以没有啥新的感悟。
连带复习了不少乱七八糟的知识,Primer这书每一页都藏着天机啊!
最重要的是,这次下来,终于是感觉对于“类”的基本知识脑中有了一套比较清晰的知识体系,再也不用像以前提到C++总会说:类和对象这东西蛋疼啊,俺学了那么久都没理明白里面的东西。
关键点都在注释里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "stdafx.h"
#include <iostream>
#include <string>
#include <set>
using namespace std;
class Item_base {
public:
trueItem_base(const string &book = " ", double sales_price = 0.0, bool dbg = false)
truetrue: isbn(book), price(sales_price), is_debug(dbg) { }
truestring book() const { return isbn; }
truevirtual double net_price(size_t n) const { return n * price; }
true// 该虚函数的基类实例返回类类型的引用或指针,则其派生类实例可以返回基类实例返回的类型的派生类
truevirtual Item_base* clone() const { return new Item_base(*this); }
truevirtual void debug(ostream&) const; // 通过is_debug数据成员控制打开或关闭调试信息
truevirtual ~Item_base() { } // 即使不做任何工作,继承层次的根类也应该定义一个虚析构函数(三法则的重要例外)
private:
truestring isbn;
protected:
truedouble price;
truebool is_debug;
};
void Item_base::debug(ostream &os = cout) const
{
trueif (!is_debug)
truetruereturn;
truecout << isbn << "\t" << price;
}
// 关键概念:重构
// 抽象基类:含有一个或多个纯虚函数
class Disc_item : public Item_base {
public:
trueDisc_item(const string &book = " ", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0, bool dbg = false)
truetrue: Item_base(book, sales_price, dbg), quantity(qty), discount(disc_rate) { }
true// 纯虚函数:该函数为后代类型提供了可以覆盖的借口,但该版本绝不会调用,用户也不能创建Disc_item类型的对象
truedouble net_price(size_t) const = 0;
truevoid debug(ostream&) const;
true~Disc_item() { }
protected:
truesize_t quantity;
truedouble discount;
};
void Disc_item::debug(ostream& os = cout) const
{
trueif (!is_debug)
truetruereturn;
trueItem_base::debug(os);
trueos << "\t" << quantity << "\t" << discount << endl;
}
class Lds_item : public Disc_item {
public:
trueLds_item(const string &book = " ", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0, bool dbg = false)
truetrue: Disc_item(book, sales_price, qty, disc_rate, dbg) { }
truedouble net_price(size_t) const;
trueLds_item* clone() const { return new Lds_item(*this); }
true~Lds_item() { }
};
double Lds_item::net_price(size_t cnt) const
{
trueif (cnt <= quantity)
truetruereturn cnt * (1 - discount) * price;
trueelse
truetruereturn cnt * price - quantity * discount *price;
}
class Bulk_item : public Disc_item {
public:
trueBulk_item(const string &book = " ", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0, bool dbg = false)
truetrue: Disc_item(book, sales_price, qty, disc_rate, dbg) { }
truedouble net_price(size_t) const;
trueBulk_item* clone() const { return new Bulk_item(*this); }
true~Bulk_item() { }
};
double Bulk_item::net_price(size_t cnt) const
{
trueif (cnt >= quantity)
truetruereturn cnt * (1 - discount) * price;
trueelse
truetruereturn cnt * price;
}
// 句柄类(包装类)
class Sales_item {
public:
trueSales_item() : p(0), use(new size_t(1)) { }
trueSales_item(const Item_base &item) : p(item.clone()), use(new size_t(1)) { }
trueSales_item(const Sales_item &i) : p(i.p), use(i.use) { ++*use; }
true~Sales_item() { decr_use(); }
trueSales_item& operator=(const Sales_item&);
true// 分别返回指针和引用,调用函数将进行动态绑定。
true// 只定义了const版本,是因为基础Item_base层次中的成员都是const成员。
trueconst Item_base* operator->() const { if (p) return p; else throw logic_error("unbound Sales_item"); }
trueconst Item_base& operator*() const { if (p) return *p; else throw logic_error("unbound Sales_item"); }
private:
trueItem_base *p;
truesize_t *use;
truevoid decr_use()
truetrue{ if (--*use == 0) { delete p; delete use; } }
};
Sales_item& Sales_item::operator=(const Sales_item &rhs)
{
true++*rhs.use;
truedecr_use();
truep = rhs.p;
trueuse = rhs.use;
truereturn *this;
}
inline bool compare(const Sales_item &lhs, const Sales_item &rhs)
{
truereturn lhs->book() < rhs->book();
}
class Basket {
true// 7.9 指向函数的指针
true// 指定了比较器的类型
truetypedef bool (*Comp)(const Sales_item&, const Sales_item&);
public:
truetypedef multiset<Sales_item, Comp> set_type;
truetypedef set_type::size_type size_type;
truetypedef set_type::const_iterator const_iter;
trueBasket() : items(compare) { } // 提供了一个名为compare的比较函数
truevoid add_item(const Sales_item &item) { items.insert(item); }
truesize_type size(const Sales_item &i) const { return items.count(i); }
truedouble total() const;
private:
truemultiset<Sales_item, Comp> items;
};
double Basket::total() const
{
truedouble sum = 0.0;
truefor (const_iter iter = items.begin(); iter != items.end(); iter = items.upper_bound(*iter))
truetruesum += (*iter)->net_price(items.count(*iter));
truereturn sum;
}
void print_total(const Item_base &item, size_t n)
{
truecout << "ISBN: " << item.book() << "\tnumber sold: " << n << "\ttotal price: " << item.net_price(n) << endl;
}
int main()
{
trueSales_item item1(Bulk_item("7-115-14554-7", 99, 20, 0.2));
trueSales_item item2(Item_base("7-115-14554-8", 39));
trueSales_item item3(Lds_item("7-115-14554-9", 50, 200, 0.2));
trueSales_item item4(Bulk_item("7-115-14554-7", 99, 20, 0.2));
trueBasket basket;
truebasket.add_item(item1);
truebasket.add_item(item2);
truebasket.add_item(item3);
truebasket.add_item(item4);
truecout << basket.total() << endl;
truesystem("pause");
truereturn 0;
}