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 }
时间: 2024-08-25 01:37:51

Chapter15:程序实例的相关文章

微信小程序实例教程(一)

序言 开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小程序」开发指南) 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果.这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志. 1. 获取微信小程序的 AppID 首先,我们需要拥有一个帐号,如果你能看到该文档,我们应当已经邀请并为你创建好一个帐号.注意不可直接使用服务号或订阅号的 AppID. 利用提供的帐号,登录https

Python学习笔记四:列表,购物车程序实例

列表 切片 中括号,逗号分隔,可以一次取出多个元素,起始位置包括,结束位置不包括(顾头不顾尾) 如果取最后一个,而且不知道列表长度,可以使用负数(-1是最后一个,以此类推) 如果取最后几个,记住从左往右数着取值,顾头不顾尾,所以如果取最后两个应该是[-2:] 从前取,如果是从0 开始,也可以省略 追加元素 a_list.append(value) 插入元素到任意位置 a_list.insert(index,value) 修改元素 a_list[index]=value 删除元素 a_list.r

使用 Bluemix? Live Sync 快速更新 Bluemix 上运行的应用程序实例

如果您要构建 Node.js 应用程序,那么可以使用 IBM® Bluemix® Live Sync 快速更新 Bluemix 上的应用程序实例,并像在桌面上进行操作一样进行开发,而无需重新部署.执行更改后,您可以立即在运行中的 Bluemix 应用程序中看到该更改.Bluemix Live Sync 可从命令行以及在 Web IDE 中运行.您可以使用 Bluemix Live Sync 来调试以 Node.js 编写的应用程序. Bluemix Live Sync 由三个功能部件组成 桌面同

Linux Epoll介绍和程序实例

1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似,事实上都I/O多路复用技术而已,并没有什么神奇的. 事实上在Linux下设计并发网络程序,向来不缺少方法,比方典型的Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及select模型和poll模型,那为何还要再引入Epoll这个东东呢?那还是有得说说

多次单击快捷方式,只运行一个程序实例

在应用程序安装之后,单击一次快捷方式,就运行一个程序实例,对于资源独占型程序来说,这样是不可以的,比如该程序使用了当前系统的某个端口,当同样的程序再次运行,再次试图占用同一个端口次,会提示"端口已经被占用的"异常.如此,必须在启动应用程序时,必须判断该程序是否已经有一个实例在运行.下面这个类中先判断该程序的实例有没有在运行,使用线程同步类EventWaitHandle(Boolean, EventResetMode, String)及注册正在等待 WaitHandle 的委托方法Reg

详解Node.js API系列C/C++ Addons(3) 程序实例

http://blog.whattoc.com/2013/09/08/nodejs_api_addon_3/ 再续前文,前文介绍了node.js 的addon用法和google v8 引擎,下面,我们进入真正的编码,下面将会通过六个例子,学习node addon 范例,了解addon编程的特性 创建一个空项目 随机数模块 向模块传递参数 回调函数处理 线程处理 对象管理 创建一个空项目 vi modulename.cpp #include <node.h> void RegisterModul

[转]一个完整的Installshield安装程序实例

Installshield安装程序实例—基本设置一 前言 Installshield可以说是最好的做安装程序的商业软件之一,不过因为功能的太过于强大,以至于上手和精通都不是容易的事情,之前都是用Installshield的Project Assistant对付过去的,这次做这个安装程序,为了实现一些功能,必须写代码,国内外现成的资料很少,而且很多都语焉不详,自己反复啃了多次,对比Installshiel自带的help,才明白资料所表达的意思.这个安装程序虽然比较简陋,在行家眼里可能是小菜一碟,但

Python编程学习,高效求解素数程序实例

素数是编程中经常需要用到的. 作为学习Python的示例,下面是一个高效求解一个范围内的素数的程序,不需要使用除法或者求模运算. 1 #coding:utf-8 #设置python文件的编码为utf-8,这样就可以写入中文注释 2 def primeRange(n): 3 myArray=[1 for x in range(n+1)] ##列表解析,生成长度为(n+1)的列表,每个数值都为1 4 myArray[0]=0 5 myArray[1]=0 6 startPos=2 7 while s

Shell程序实例集锦一

2007-12-13 07:51:40 标签:实例 程序 Shell 休闲 职场 Shell程序实例集锦一      前言:下面这些hell实例都是自己写的或者用过的一些Shell小程序.整理整理.    ——Ajian 1.删除B文件中和A文件相同的内容 #!/bin/sh# Ajianfor file in `cat a.list | cut -d. -f1`dosed -i '/'$file'/d' b.listdone   2.根据文件名的前四位创建二级目录 #!/bin/sh#Ajia