c++primer 例子文本程序再探
来源:互联网 发布:ubuntu 12.04 安装jdk 编辑:程序博客网 时间:2024/06/01 08:44
先附上前面的basket类的例子,里面很多思想也是我需要学的
#include <iostream>#include <string>#include <set>#include <memory>//买书的类class quote{ friend double print_total(std::ostream &os, quote &q, std::size_t sz); public: quote() = default; quote(const std::string &book, double p): bookNo(book), price(p) { } quote(const quote &q): bookNo(q.bookNo), price(q.price) { } quote(quote &&q): //一个右值拷贝 bookNo(q.bookNo), price(q.price) { } quote& operator=(const quote &q) { bookNo = q.bookNo; price = q.price; return *this; } virtual double net_price(std::size_t sz)const { return price * sz; } const std::string& isbn()const { return bookNo; } //注意动态内存分配问题,基类和派生类的内存大小不同 //所以我们写了个分配函数,且必须定义为虚函数。为了实现后面的动态分配 //后面跟着成员限定符说明是用作左值还是右值 virtual quote* clone()const& { return new quote(*this); } virtual quote* clone() && { return new quote(std::move(*this)); } protected: double price; private: std::string bookNo;};double print_total(std::ostream &os, quote &q, std::size_t sz){ double ret = q.net_price(sz); os << q.isbn() << " " << q.price << " " << ret << "\n"; return ret;}//抽象基类,因为打折有许多不同的措施,但都基于discount和disc_num//简单来说抽象出来一个标准,discount和disc_num 就可以说是一个标准。class disc_quote : public quote{ public: disc_quote() = default; disc_quote(const std::string &book, double p, double disc, std::size_t num): quote(book, p), discount(disc), disc_num(num) { } double net_price(std::size_t sz)const = 0; //纯虚函数 protected: double discount; std::size_t disc_num; private:};//第一种打折方式class one_bulk_quote : public disc_quote{ public: using disc_quote::disc_quote; double net_price(std::size_t sz)const override { if(sz > disc_num) { return sz * price * discount; } else { return sz * price; } } //对第一种打折类实现动态分配 one_bulk_quote* clone()const & { return new one_bulk_quote(*this); } one_bulk_quote* clone() && { return new one_bulk_quote(std::move(*this)); } protected: private:};class two_bulk_quote : public disc_quote{ public: using disc_quote::disc_quote; double net_price(std::size_t sz) { if(sz > disc_num) { return (sz-disc_num) * price * discount + disc_num * price; } else { return sz * price; } } protected: private:};class basket{ public: //void add_item(const std::shared_ptr<quote>&sale) //{ // items.insert(sale); //} //如果像上面那样写分配内存不会是动态决定的,参数传递是quote,那么无论传参是什么分配都是quote,如果是派生类就会被砍掉一部分。 void add_item(const quote &sale) { items.insert(std::shared_ptr<quote>(sale.clone())); } void add_item(quote && sale) { items.insert(std::shared_ptr<quote>(std::move(sale).clone())); } double total_receipt(std::ostream &os)const; protected: private: //自定义比较函数 static bool compare(const std::shared_ptr<quote> &lhs, const std::shared_ptr<quote> &rhs) { return lhs->isbn() < rhs->isbn(); } std::multiset<std::shared_ptr<quote>, decltype(compare)*> items{compare};//decltype不能推断出指针和引用};double basket::total_receipt(std::ostream &os)const{ double sum = 0.0; //注意下upper_bound的作用 for(auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)) { sum += print_total(std::cout, **iter, items.count(*iter)); } os << "total Sale: " << sum << std::endl; return sum;}int main(){}
文本程序
#ifndef _TEXTQUERY_H_#define _TEXTQUERY_H_#include <iostream>#include <map>#include <set>#include <fstream>#include <sstream>#include <memory>#include <vector>#include <string>#include <algorithm>class QueryResult;class TextQuery;using line_no = std::vector<std::string>::size_type;class QueryResult{ friend class TextQuery; friend std::ostream& operator<<(std::ostream &os, const QueryResult &q); public: QueryResult() = default; QueryResult(std::string s, std::shared_ptr<std::set<line_no>>li, std::shared_ptr<std::vector<std::string>>wf): q_word(s), lines(li), wordfile(wf) { } std::set<line_no>::iterator begin(); std::set<line_no>::iterator end(); std::shared_ptr<std::vector<std::string>> get_file(); private: std::string q_word; //要查询单词 std::shared_ptr<std::set<line_no>>lines; //出现行号 std::shared_ptr<std::vector<std::string>>wordfile; //单词文件};class TextQuery{ friend class QueryResult; public: TextQuery() = default; TextQuery(std::ifstream &is); QueryResult query(const std::string &s)const; private: std::shared_ptr<std::vector<std::string>>m_file; std::map<std::string, std::shared_ptr<std::set<line_no>>>m_word_line; //考虑共享数据的需求 }; //Query_base 抽象基类,制定一个标准class Query_base{ friend class Query; protected: virtual ~Query_base() = default; private: // virtual QueryResult eval(const TextQuery &)const = 0; virtual std::string rep()const = 0;};//接口类,基类包括派生类都可以通过Query来使用,隐藏实现class Query{ friend Query operator~(const Query &); friend Query operator&(const Query &, const Query &); friend Query operator|(const Query &, const Query &); friend std::ostream& operator<<(std::ostream &os, const Query &query); public: Query(const std::string&);//wait WordQuery //Query是Query_base的唯一接口,所以必须定义纯虚函数 //且Query就可以通过指针来调用派生类各自Query_base虚函数 QueryResult eval(const TextQuery &t)const { return q->eval(t); } std::string rep()const { return q->rep(); } private: //构造函数定义为private,不希望一般用户随便定义Query_base对象。 Query(std::shared_ptr<Query_base> query):q(query) { } //通过智能指针实现动态绑定 std::shared_ptr<Query_base> q;};//派生类class WordQuery: public Query_base{ friend class Query; WordQuery(const std::string &s):query_word(s) { } //具体的类 QueryResult eval(const TextQuery &t)const { return t.query(query_word); } std::string rep()const { return query_word; } std::string query_word; //要查找的单词};//无论哪种查询都是建立在WordQuery的根本上,So Query的构造函数用一个WordQuery来初始化inline Query::Query(const std::string &s): q(new WordQuery(s)) { }class NotQuery: public Query_base{ friend Query operator~(const Query &); NotQuery(const Query &q):query(q) { } //具体的类,覆盖掉纯虚函数 std::string rep()const { return "~(" + query.rep() + ")"; } QueryResult eval(const TextQuery &)const; Query query;};inline Query operator~(const Query &operand){ //注意返回值 return std::shared_ptr<Query_base>(new NotQuery(operand));}//两个运算符的抽象基类class BinaryQuery: public Query_base{ protected: BinaryQuery(const Query &l, const Query &r, std::string s): lhs(l), rhs(r), opSym(s) { } std::string rep()const { return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; } //eval函数没有定义,继承了纯虚函数,还是抽象基类 Query lhs, rhs; std::string opSym;};class AndQuery: public BinaryQuery{ friend Query operator&(const Query&, const Query&); AndQuery(const Query &left, const Query &right): BinaryQuery(left, right, "&") { } //具体的类,覆盖了eval并且继承了rep QueryResult eval(const TextQuery&) const;};inline Query operator&(const Query&lhs, const Query&rhs){ return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));}class OrQuery: public BinaryQuery{ friend Query operator|(const Query&, const Query&); OrQuery(const Query &left, const Query &right): BinaryQuery(left, right, "|") { } //具体的类,覆盖了eval并且继承了rep QueryResult eval(const TextQuery&)const;};inline Query operator|(const Query&lhs, const Query&rhs){ return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));}
#include "textquery.h"std::ostream& operator<<(std::ostream &os, const QueryResult &q){ os << "element occurs:" << q.lines->size() << " times\n"; for(line_no i : *q.lines) { os << " " << "line(" << i+1 << ") "; os << *(q.wordfile->begin()+i) << "\n"; //os << (*(q.wordfile))[i] << "\n"; //注意运算符优先级 } return os;}TextQuery::TextQuery(std::ifstream &is):m_file(new std::vector<std::string>){ std::string word; std::string line; static int i = 0; while(std::getline(is, line)) { //行号 m_file->push_back(line); i = m_file->size()-1; std::istringstream ist(line); while(ist >> word) { auto &li = m_word_line[word]; //返回set的shared_ptr if(!li) li.reset(new std::set<line_no>); li->insert(i); } }}QueryResult TextQuery::query(const std::string &s)const{ static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>); auto ret = m_word_line.find(s); if(ret == m_word_line.end()) return QueryResult(s, nodata, m_file); else return QueryResult(s, ret->second, m_file);}std::ostream& operator<<(std::ostream &os, const Query &query){ //query.rep()内部还是通过指针来调用的,是需调用 return os << query.rep();}//QueryResultstd::set<line_no>::iterator QueryResult::begin(){ return lines->begin();}std::set<line_no>::iterator QueryResult::end(){ return lines->end();}std::shared_ptr<std::vector<std::string>> QueryResult::get_file(){ return wordfile;}//evalQueryResultOrQuery::eval(const TextQuery &text)const{ auto right = rhs.eval(text), left = lhs.eval(text); auto ret_lines = std::make_shared<std::set<line_no>>(left.begin(), left.end()); ret_lines->insert(right.begin(), right.end()); return QueryResult(rep(), ret_lines, left.get_file());}QueryResultAndQuery::eval(const TextQuery &text)const{ auto left = lhs.eval(text), right = rhs.eval(text); auto ret_lines = std::make_shared<std::set<line_no>>(); set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin())); return QueryResult(rep(), ret_lines, left.get_file());}QueryResultNotQuery::eval(const TextQuery &text)const{ auto result = query.eval(text); auto ret_lines = std::make_shared<std::set<line_no>>(); auto beg = result.begin(), end = result.end(); auto sz = result.get_file()->size(); //相当于两个集合两个指针一起走。 for(std::size_t n = 0; n != sz; ++n) { if(beg == end || *beg != n) ret_lines->insert(n); else if(beg != end) ++beg; } return QueryResult(rep(), ret_lines, result.get_file());}
#include "textquery.h"int main(int argc, char *argv[]){ std::ifstream is(argv[1]); TextQuery t1(is); std::string word; Query q = Query("fiery") & Query("bird") | Query("wind"); //Query q = Query("fiery"); //Query q = Query("A"); std::cout << q << std::endl; std::cout << q.eval(t1) << std::endl;}
运行结果:
这个例子自己也看了挺久,感觉还是有点复杂,可能是自己写的这种面向对象的不多吧,还要多加联系。
这个例子中的很多思想非常好,值得我们去学习。
总结:
1.好好体会抽象基类纯虚函数这个概念,在c++面向对象编程是非常重要的。
1 0
- c++primer 例子文本程序再探
- 【C++ Primer】文本查询程序再探
- C++primer学习:面向对象程序设计(5):再探文本查询程序
- c++primer 实现文本统计的程序
- 文本查询程序--摘自c++primer
- 【足迹C++primer】41、文本查询程序
- 【足迹C++primer】56、文本查询程序
- C++Primer 【笔记】文本查询程序 TextQuery
- C++primer学习:文本查询程序
- C++ Primer 第15章例子-文本查询程序
- c++ primer 5ed 15.9文本查询程序再探
- c++primer里的文本查询程序扩展
- C++ primer 文本查询程序
- <<c++ primer>>文本查询程序
- C++primer 文本查询练习
- c++primer 文本查询 源代码
- c++primer文本查询系统
- C++primer书店程序
- php-fpm---为每个开发人员分配进程
- SQL Server 2008数据类型
- 一次MySQL主从搭建出现“Last_IO_Errno: 1236”错误的处理记录
- Android 打开关闭硬件加速
- Facebook POP动画简单使用
- c++primer 例子文本程序再探
- ubuntu下配置java环境变量的方法
- 典型算法——质数判断
- 头文件重复引用
- C#编辑框添加水印
- 前端开发规范之html编码规范
- 【并发】Java并发的四种风味:Thread、Executor、ForkJoin和Actor
- Property Animation:PropertyValuesHolder
- Linux vim 基本使用(二)