先附上前面的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();
}
//QueryResult
std::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;
}
//eval
QueryResult
OrQuery::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());
}
QueryResult
AndQuery::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());
}
QueryResult
NotQuery::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++面向对象编程是非常重要的。