首页 > 代码库 > Chapter15:程序实例

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) const10     {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 Quote38 {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 Quote44 {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) const50 {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     else57         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) const107 {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) const117 {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 }

 

Chapter15:程序实例