Chapter15:程序实例

购物篮程序:模拟虚拷贝

 1 class Basket
 2 {
 3 public:
 4     //使用合成的默认构造函数和拷贝控制
 5     void add_item(const shared_ptr<Quote> &sale)
 6     {
 7         items.insert(sale);
 8     }
 9     double total_recipt(ostream& os) const
10     {
11         double sum = 0.0;
12         for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter))
13         {
14             sum += print_total(os, **iter, items.count(*iter));
15         }
16     }
17 private:
18     static bool compare(shared_ptr<Quote> &lhs, shared_ptr<Quote> &rhs)
19     {
20         return lhs->isbn() < rhs.isbn();
21     }
22     multiset<shared_ptr<Quote>, decltype(compare)*> items{ compare };
23 
24 };
25 
26 //使用方法
27 Basket bsk;
28 bsk.add_item(make_shared<Quote>("123", 45));
29 bsk.add_item(make_shared<Bulk_quote>("345", 45,3,15));
30 
31 //我们想这么使用,即:add_item负责内存的分配与管理
32 bsk.add_item(Quote("123", 45));
33 bsk.add_item(Bulk_quote("345", 45, 3, 15));
34 
35 //问题是,我们无法通过参数的类型Quote,来得知应该分配什么样的内存,Quote or Bulk_quote?
36 //解决方法:模拟虚拷贝
37 class Quote
38 {
39 public:
40     virtual Quote* clone() const & { return new Quote(*this); }
41     virtual Quote* clone() && {return new Quote(std::move(*this)); }
42 };
43 class Bulk_quote:public Quote
44 {
45 public:
46     virtual Bulk_quote* clone() const & { return new Bulk_quote(*this); }
47     virtual Bulk_quote* clone() && {return new Bulk_quote(std::move(*this)); }
48 };
49 
50 void add_item(const Quote &sale)
51 {
52     items.insert(shared_ptr<Quote>(sale.clone()));
53 }
54 void add_item(Quote &&sale)
55 {
56     items.insert(shared_ptr<Quote>(std::move(sale).clone()));
57 }

 

文本查询程序(2):允许单词的逻辑组合查询如:fiery&bird|wind

分析:

我们只需要对于TextQuery,定义operator~(),operator|(TextQuery1,TextQuery2),operator&(TextQuery1,TextQuery2)即可完成任务。

我们这样使用:TextQuery(fiery)&TextQuery(brid)|TextQuery(wind),会出现三个TextQuery对象。

逻辑上来讲,文本文档对象TextQuery只需要一个。其实,真正需要多个操作的是查询这一操作。我们现在有必要将查询这一操作分离出来。

 

之前的查询是一个函数[参见 Chapter12&Chapter13程序实例]:

47 //如果没有找到string,应该返回什么?
48 //我们定义一个局部static对象,它指向一个空行号set的shared_ptr,未找到单词,则返回此对象的一个拷贝
49 QueryResult TextQuery::query(const string &sought) const
50 {
51     static shared_ptr<set<line_no>> nodata(new set<line_no>);
52     //不使用下标运算符来查找,避免将单词添加到wm中
53     auto loc = wm.find(sought);
54     if (loc == wm.end())
55         return { sought, nodata, file };
56     else
57         return { sought, loc->second, file };
58 }

现在我们把它分离出来,重新写作一个类Query,然后定义operator~,operator|,operator&即可。

但是书中为了演示继承,所以把操作设计成继承体系。

每个查询类只包含两个操作:

eval,接受一个TextQuery对象,返回一个QueryResult;

rep,返回基础查询的string表示形式。

具体的类设计细节参见书本。

然后使用Query类隐藏继承体系。

所以Query_base的所有函数都是私有的。(私有虚函数竟然可以被派生基类访问?Query不是NotQuery的友元,亦可以调用私有虚函数??

  1 class Query_base
  2 {
  3     friend class Query;
  4 protected:
  5     using line_no = TextQuery::line_no;
  6     virtual ~Query_base() = default;
  7 private:
  8     virtual QueryResult eval(const TextQuery&) const = 0;
  9     virtual string rep() const = 0;
 10 };
 11 
 12 class Query
 13 {
 14     friend Query operator~(const Query&);
 15     friend Query operator|(const Query&, const Query&);
 16     friend Query operator&(const Query&, const Query&);
 17 public:
 18     Query(const string&);//要生成WordQuery,WordQuery定义之后再定义;
 19     QueryResult eval(const TextQuery &t) const { return q->eval(t); }
 20     string rep() const { return q->rep(); }
 21 private:
 22     Query(shared_ptr<Query_base> query) :q(query) {}
 23     shared_ptr<Query_base> q;
 24 };
 25 
 26 ostream& operator<<(ostream &os, const Query &query)
 27 {
 28     return os << query.rep();
 29 }
 30 
 31 
 32 //Query_base的继承体系
 33 class WordQuery :public Query_base
 34 {
 35     friend class Query;
 36     WordQuery(const string& s) :query_word(s) {}
 37     QueryResult eval(const TextQuery &t) const { return t.query(query_word); }
 38     string rep() const { return query_word; }
 39     string query_word;
 40 };
 41 //注意,Query只是Query_base和WordQuery的友元
 42 inline Query::Query(const string &s)
 43     :q(new WordQuery(s)) {}
 44 
 45 
 46 class NotQuery :public Query_base
 47 {
 48     friend Query operator~(const Query&);
 49     NotQuery(const Query& q):query(q){}
 50     string rep()const { return "~(" + query.rep() + ")"; }
 51     QueryResult eval(const TextQuery&) const;
 52     Query query;
 53 };
 54 
 55 inline Query operator~(const Query &oprand)
 56 {
 57     return shared_ptr<Query_base>(new NotQuery(oprand));
 58 }
 59 
 60 class BinaryQuery :public Query_base
 61 {
 62     //抽象基类,Query不访问,故不用friend
 63 protected:
 64     BinaryQuery(const Query &l, const Query &r, string s)
 65         :lhs(l), rhs(r), opSym(s) {}
 66     string rep() const { return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; }
 67     Query lhs, rhs;
 68     string opSym;
 69 };
 70 
 71 class AndQuery :public BinaryQuery
 72 {
 73     friend Query operator&(const Query&, const Query&);
 74     AndQuery(const Query &left, const Query &right)
 75         :BinaryQuery(left, right, "&") {}
 76     QueryResult eval(const TextQuery&) const;
 77 };
 78 
 79 inline Query operator&(const Query &lhs, const Query &rhs)
 80 {
 81     return shared_ptr<Query_base>(new AndQuery(lhs, rhs));
 82 }
 83 
 84 class OrQuery :public BinaryQuery
 85 {
 86     friend Query operator|(const Query&, const Query&);
 87     OrQuery(const Query &left, const Query &right)
 88         :BinaryQuery(left, right, "|") {}
 89     QueryResult eval(const TextQuery&) const;
 90 };
 91 
 92 inline Query operator|(const Query &lhs, const Query &rhs)
 93 {
 94     return shared_ptr<Query_base>(new OrQuery(lhs, rhs));
 95 }
 96 
 97 QueryResult OrQuery::eval(const TextQuery &text) const
 98 {
 99     auto right = rhs.eval(text), left = lhs.eval(text);
100 
101     auto ret_lines = make_shared<set<line_no>>(left.begin(), left.end());
102     ret_lines->insert(right.begin(), right.end());
103     return QueryResult(rep(), ret_lines, left.get_file());
104 }
105 
106 QueryResult AndQuery::eval(const TextQuery &text) const
107 {
108     auto right = rhs.eval(text), left = lhs.eval(text);
109 
110     auto ret_lines = make_shared<set<line_no>>();
111     set_intersection(left.begin(), left.end(), right.begin(), right.end(),inserter(*ret_lines,ret)lines->begin()));
112     return QueryResult(rep(), ret_lines, left.get_file());
113 
114 }
115 
116 QueryResult NotQuery::eval(const TextQuery &text) const
117 {
118     auto result = query.eval(text);
119     auto ret_lines = make_shared<set<line_no>>();
120     auto beg = result.begin(), end = result, end();
121     auto sz = result.get_file()->size();
122     for (size_t n = 0; n != sz; ++n)
123     {
124         if (beg == end || *beg != n)
125             ret_lines->insert(n);
126         else if (beg != end)
127             ++beg;
128     }
129 
130     return QueryResult(rep(), ret_lines, result.get_file());
131 }

 

posted @ 2016-09-09 10:53  wangyanphp  阅读(177)  评论(0编辑  收藏  举报