《C++ Primer》中第15章为了讲解面向对象编程,举了一个例子:设计一个小程序,能够处理查询给定word在文件中所在行的任务,并且能够处理“非”查询,“或”查询,“与”查询。例如执行查询 one & of |the ,表示对单词one和of的查询结果取交集,然后对单词the的查询结果取并集。

  书中查询的底层操作实际定义在类TextQuery中,我们在TextQuery的基础上,进一步封装并实现如下图所示的类结构,能够达到上述功能需求。类之间的结构如下图所示:

  

  程序扼要设计如下表所示:

  在此基础之上,可以写出下述代码。代码已经详细注释,具体实现细节不再赘述。

#include <iostream>
#include <set>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
#include <map>using namespace std;class TextQuery {
public://执行查找,返回单词所在行号组成的setset<int> run_query(const string &word) const {auto it = word_map.find(word);if (it == word_map.end())return set<int>();return it->second;}//返回line行对应的字符串string text_line(int line) const {if (line < lines_of_text.size())return lines_of_text[line];throw out_of_range("line number out of range");}//返回vector中存储的行的数目int size() const {return lines_of_text.size();}//读取文件,建立键值对映射关系void read_file(ifstream &is) {store_file(is);build_map();}private://从文件输入流in中读取行,并将其存储在vector中void store_file(ifstream &is) {string textline;while (getline(is, textline))lines_of_text.push_back(textline);}//建立单词 和行号组成的键值对映射关系void build_map() {for (int line_no = 0; line_no != lines_of_text.size(); line_no++) {string text_line = lines_of_text[line_no];istringstream line(text_line);string word;while (line >> word) {word_map[word].insert(line_no);}}}//存储所有的行vector<string> lines_of_text;//存储单词,行号键值对map<string, set<int>> word_map;
};//显示查询结果
void print_results(const set<int> &locs, const TextQuery &file) {if (locs.empty()) {cout << endl << "Sorry. There are no entries for your query." << endl << "Try again." << endl;return;}//输出行号和对应的行for (auto it = locs.begin(); it != locs.end(); it++) {cout << "\t" << "(line "<< (*it) + 1 << ") "<< file.text_line(*it) << endl;}
}//打开文件,返回文件输入流
ifstream &open_file(ifstream &in, const string &file) {in.close();in.clear();in.open(file.c_str());return in;
}class Query_base {friend class Query;protected:virtual ~Query_base() { }private://定义纯虚函数,对TextQuery对象执行查询virtual set<int> eval(const TextQuery &) const = 0;//输出查询结果virtual ostream &display(ostream & = cout) const = 0;
};
//对单词执行查询
class WordQuery : public Query_base {friend class Query;WordQuery(const string &s) : query_word(s) { }//执行查询,返回查询的结果set<int> eval(const TextQuery &t) const {return t.run_query(query_word);}//输出查询结果ostream &display(ostream &os) const {return os << query_word;}//要查询的单词string query_word;
};class Query {//这些函数能够隐式调用private中的构造函数 Query(Query_base *query),创建Query对象friend Query operator~(const Query &);friend Query operator|(const Query &, const Query &);friend Query operator&(const Query &, const Query &);public://对要查询的单词初始化Query对象Query(const string &s) : q(new WordQuery(s)), use(new int(1)) {}//复制构造函数Query(const Query &c) : q(c.q), use(c.use) {++*use;}//析构函数~Query() {decr_use();}//重载运算符=Query &operator=(const Query &);//对TextQuery 执行查询任务set<int> eval(const TextQuery &t) const {return q->eval(t);}ostream &display(ostream &os) const {return q->display(os);}private://友元重载函数可以访问Query(Query_base *query) : q(query), use(new int(1)) { }Query_base *q;int *use;//减少引用计数的值,如果引用计数的值为0,那么删除对象void decr_use() {if (--*use == 0) {delete q;delete use;}}
};
//重载运算符 = ,减少本对象的引用计数,同时增加要复制的对象的引用计数
Query &Query::operator=(const Query &rhs) {++*rhs.use;decr_use();q = rhs.q;use = rhs.use;return *this;
}
//重载运算符 <<
ostream &operator<<(ostream &os, const Query &q) {return q.display(os);
}class BinaryQuery : public Query_base {
protected:BinaryQuery(Query left, Query right, string op) : lhs(left), rhs(right), oper(op) { }//输出 查询 操作ostream &display(ostream &os) const {return os << "(" << lhs << " " << oper << " " << rhs << ")";}//左右两个操作数const Query lhs, rhs;//运算符const string oper;
};class AndQuery : public BinaryQuery {//友元重载运算符函数可以访问构造器函数 Query(Query_base *query)friend Query operator&(const Query &, const Query &);AndQuery(Query left, Query right) : BinaryQuery(left, right, "&") { }//查询实际上是对左右操作数的查询结果取交集set<int> eval(const TextQuery &file) const {set<int> left = lhs.eval(file);set<int> right = rhs.eval(file);set<int> ret;set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(ret, ret.begin()));return ret;}
};class OrQuery : public BinaryQuery {//友元重载运算符函数可以访问构造器函数Query(Query_base *query)friend Query operator|(const Query &, const Query &);OrQuery(Query left, Query right) : BinaryQuery(left, right, "|") { }//查询实际上是对左右操作数的查询结果取并集set<int> eval(const TextQuery &file) const {set<int> left = lhs.eval(file);set<int> right = rhs.eval(file);left.insert(right.begin(), right.end());return left;}
};class NotQuery : public Query_base {//友元重载运算符函数可以访问构造器函数 Query(Query_base *query)friend Query operator~(const Query &);NotQuery(Query q) : query(q) { };//执行的查询实际上是对左右两个操作数的查询结果取差集set<int> eval(const TextQuery &file) const {auto result = query.eval(file);set<int> ret;for (int n = 0; n != file.size(); n++) {if (result.find(n) == result.end())ret.insert(n);}return ret;}ostream &display(ostream &os) const {return os << "~" << query << ")";}const Query query;
};//重载运算符 &
inline Query operator&(const Query &lhs, const Query &rhs) {return new AndQuery(lhs, rhs);
}//重载运算符 |
inline Query operator|(const Query &lhs, const Query &rhs) {return new OrQuery(lhs, rhs);
}//重载运算符 ~
inline Query operator~(const Query &oper) {return new NotQuery(oper);
}//创建TextQuery实例
TextQuery build_textfile(const string &filename) {ifstream infile;if (!open_file(infile, filename)) {cerr << "can't open input file!" << endl;return TextQuery();}TextQuery ret;ret.read_file(infile);return ret;
}int main() {TextQuery file = build_textfile("/Users/zhouyang/Desktop/text.txt");string word1, word2, word3;while (cin >> word1 >> word2 >> word3) {Query q = Query(word1) & Query(word2) | Query(word3);cout << "Executing Query for: " << q << endl;auto result = q.eval(file);print_results(result, file);}return 0;
}

执行查询: one & of |the , 结果如下:

one of the
Executing Query for: ((one & of) | the)(line 1) Many in the US believe the use of the nuclear bomb, though devastating, was right, because it forced Japan to surrender, bringing an end to World War Two.(line 2) The daughter of one survivor, who was visiting the memorial on Friday, said the suffering had "carried on over the generations".(line 3) "That is what I want President Obama to know," Han Jeong-soon, 58, told the Associated Press news agency. "I want him to understand our sufferings."(line 4) Seiki Sato, whose father was orphaned by the bomb, told the New York Times: "We Japanese did terrible, terrible things all over Asia. That is true. And we Japanese should say we are sorry because we are so ashamed, and we have not apologised sincerely to all these Asian countries. But the dropping of the atomic bomb was completely evil."(line 6) Media captionFilmmaker Barry Frechette told Shigeaki Mori's story in the film Paper Lanterns(line 9) China responded to the visit by saying that Japan's six-week attack on the Chinese city of Nanjing, which began in December 1937, was more worthy of reflection.(line 10) The Chinese say 300,000 people were killed, although other sources say the figure was lower.(line 12) 'Just listen' - Japan's media on the visit(line 13) The Chugoku Shimbun urges Mr Obama to "hear the voices of Hiroshima". "The people of Hiroshima will be watching the president closely, eyeing to what extent he is truly resolved to advance the abolition of nuclear arms," it said.(line 14) The Asahi Shimbun carries an article saying Mr Obama's "gestures will shape the visit", with the "most powerful gesture" being to "just listen to the bomb victims' memories of suffering and activism".(line 15) The Japan Times says: "To truly pay homage to those whose lives were lost or irrevocably altered by the Hiroshima and Nagasaki bombings, Obama's visit must galvanise the international community to move without delay toward a world free of nuclear weapons. The fact that these weapons have not been used over the past 70 years does not guarantee a risk-free future for our children."(line 20) The bomb was nicknamed "Little Boy" and was thought to have the explosive force of 20,000 tonnes of TNT(line 21) Paul Tibbets, a 30-year-old colonel from Illinois, led the mission to drop the atomic bomb on Japan(line 22) The Enola Gay, the plane which dropped the bomb, was named in tribute to Col Tibbets' mother(line 23) The final target was decided less than an hour before the bomb was dropped. The good weather conditions over Hiroshima sealed the city's fate(line 24) On detonation, the temperature at the burst-point of the bomb was several million degrees. Thousands of people on the ground were killed or injured instantly(line 25) The hours before the bomb was dropped

转载于:https://www.cnblogs.com/zhoudayang/p/5539916.html

《C++ Primer》 chapter 15 TextQuery相关推荐

  1. 《C++ Primer》第15章 15.4节习题答案

    <C++ Primer>第15章 面向对象程序设计 15.4节 抽象基类 习题答案 练习15.15:定义你自己的Disc_quote和Bulk_quote. [出题思路]本题练习实现不同折 ...

  2. 《C++ Primer》第15章 15.2节习题答案

    <C++ Primer>第15章 面向对象程序设计 本章介绍了面向对象程序设计的两个重要概念:继承和动态绑定,包括: □●继承.基类.派生类的基本概念. □●虚函数和虚基类. □●继承中的 ...

  3. 《C++ Primer》第12章 12.3节习题答案

    <C++ Primer>第12章 动态内存 12.3节使用标准库:文本查询程序 习题答案 练习12.27:TextQuery和QueryResult类只使用了我们已经介绍过的语言和标准库特 ...

  4. C++自学笔记_文本查询程序_《C++ Primer》

    <C++ Primer> 第10章结束,用一个文本查询程序结束本章 :) 程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在 ...

  5. 如何利用《C++ Primer》学习C++?

    <C++ Primer>作为久负盛名的C++经典教程,丰富的教学辅助内容.精心组织的编程示范,无论是初学者入门,或是中.高级程序员提升,都是不容置疑的首选. 一本好书只有读过才有价值,然而 ...

  6. 《C++ Primer》第14章 14.3节习题答案

    <C++ Primer>第14章 操作重载与类型转换 14.3节  算术和关系运算符  习题答案 练习14.13:你认为Sales_data类还应该支持哪些其他算术运算符(参见表4.1,第 ...

  7. 《C++ Primer》学习笔记

    这次一定要完整学完 2022/8/24 像编辑器一样思考和理解C++ C++的编程风格:C风格.基于对象.面向对象.泛型和基于组件. 初学建议<C++Primer>和<C++标准程序 ...

  8. 《C++Primer》第九章-顺序容器-学习笔记(1)-顺序容器定义与操作

    <C++Primer>第九章-顺序容器-学习笔记(1) 文章目录 <C++Primer>第九章-顺序容器-学习笔记(1) 摘要 顺序容器的定义 容器元素的初始化 将一个容器初始 ...

  9. 《C++ Primer》第13章 13.5节习题答案

    <C++ Primer>第13章 拷贝控制 13.5节 动态内存管理类 习题答案 练习13.39:编写你自己版本的StrVec,包括自己版本的reserve.capacity(参见9.4节 ...

最新文章

  1. K-means算法(理论+opencv实现)
  2. mysql之存储引擎的选择
  3. python无法打开_如何解决Windows命令行无法运行python文件?
  4. 使用虚拟按钮(Ghost Buttons)的25个网站
  5. GDAL读取S-57海图数据中文属性值乱码问题解决(续)
  6. 获得Azure订阅LoadBalancer的脚本
  7. 【交换机在江湖】第十四章 VLAN通信篇
  8. AE插件 点线面三维粒子插件 Plexus Mac v3.1.8破解版
  9. Github优秀开源项目
  10. 【树莓派】USB摄像头+python+opencv
  11. win7计算机属性恢复,win7怎么打开系统还原功能?win7打开系统还原功能的方法步骤...
  12. android移动开发软件安装,android studio 开发的安卓软件怎么安装到手机上
  13. Android Activity中实现Fragment切换功能效果
  14. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
  15. win10计算机管理没有蓝牙,win10系统中缺少打开或关闭蓝牙选项的解决方法
  16. javaScript解决浏览器兼容问题,判断浏览器是ie或者Chrome
  17. 在墙上找垂直线_红外线水平仪如何看墙面垂直
  18. 全国青少年软件编程等级考试scratch二级考试大纲+考点
  19. 《DeepLung: Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》网络模型解读
  20. ZIP炸弹怎样反击扫描器?

热门文章

  1. 安科瑞AFL-T系列分流器最大额定电流10kA,结构上≤50A时采用塑料底座固定安装,>50A时直接用铜端子固定安装
  2. Android安全机制(二)
  3. 人物-发明家-爱迪生:*托马斯·阿尔瓦·爱迪生
  4. Java支付宝沙箱环境支付,官方Demo远程调试【内网穿透】
  5. 一些SQL语句的实现
  6. contos7 安装Redis
  7. 2013.4.22每日一记
  8. 离开Facebook后,Caffe创始人贾扬清加入阿里巴巴
  9. c语言实现动态字符串,C语言怎么实现可变长度字符串
  10. 针对基于Phison(群联)U盘的BadUSB攻击