这一节初步探讨了如何设计一个继承类体系。
为我们前面所写的文本探测程序添加以下功能:
(1):可以将查询结果进行|,&,~的运算.运算的优先级按照C++规定的表达式来进行.如Query(“hair”)|Query(“bird”);
(2) : 添加一个历史系统,能够查询前面的进行的某个查询.并可以在其中增加内容并与其他查询组合.
(3):允许用户在查询的时候做出限制,从给定范围中挑出匹配的行显示.
这个体系的设计相对比较复杂,Textquery类负责进行基础的读入文件,Queryresult类负责保存结果.而我们重新定义一个继承体系Query_base继承体系,用Wordquery类,AndQuery类,OrQuery类负责保存信息.eval()函数负责解析结果,rep()函数负责打印查询的单词逻辑表达式.用Query类作为一个体系的接口类,掩盖整个体系,同时也减少用户操作难度.
同时对一些边界条件进行了检测,防止出错.
#ifndef Query_base_01
#define Query_base_01
#include "Textquery.h"
#include "iterator"
#include "memory"
using namespace std;
/************抽象基类query_base********************/
class Query;
class Query_base
{
friend Query& history_query(size_t n);
friend class Query;
public:
static vector<shared_ptr<Query>> history;
private:
virtual QueryResult eval(const Textquery&)const = 0;
/******************重载这个虚函数,接受限制范围的行数******************/
virtual QueryResult eval(const Textquery&,size_t,size_t)const;
virtual string rep()const = 0;
protected:
Query_base() = default;
};
/***************重载eval*****************/
QueryResult Query_base::eval(const Textquery& t, size_t min, size_t max)const
{
auto res = eval(t);
auto dest = make_shared<set<size_t>>();
remove_copy_if(res.begin(), res.end(), inserter(*dest, (*dest).begin()),
[&](size_t q){ return (q<min || q>max); });
return QueryResult(rep(), res.get_file(), dest);
}
vector<shared_ptr<Query>>Query_base::history {shared_ptr<Query>()};
/********定义一个接口类 Query,简化用户操作的复杂度,也可以减少类设计时的一些复杂度********/
class Query
{
friend Query operator~(const Query&);
friend Query operator&(const Query&, const Query&);
friend Query operator|(const Query&, const Query&);
public:
/*******构造函数,接受一个string,返回一个wordquery的指针*************/
Query(const string& s);
/**********覆盖eval的两种形式**************************/
QueryResult eval(const Textquery& t)const { return q->eval(t); };
QueryResult eval(const Textquery& t, size_t min, size_t max){
return q->eval(t, min, max);
}
/***************输出查询的单词*********************************/
virtual string rep()const { return q->rep(); };
/*************历史查询系统,返回前面第n次的查询结果**************************/
/************************添加记录****************************************************/
void add_history()const{
shared_ptr<Query> p = make_shared<Query>(*this);
q->history.push_back(p);
}
private:
/**************私有构造函数,接受指向其他Query_base的智能指针,用于运算符&|~*************/
Query(shared_ptr<Query_base> p) :q(p){}
shared_ptr<Query_base> q;
};
/*********************历史查询************/
Query& history_query(size_t n)
{
size_t len = Query_base::history.size();
if (!(Query_base::history.empty()) && n>0 && n <= len)
return *(Query_base::history[len - n]);
else
throw::out_of_range("invaild n or empty history");
}
/*******************Wordquery类**************************/
class Wordquery :public Query_base
{
friend class Query;
/*************该构造函数自动调用Query_Base(),虽然没有可初始化的******************************/
Wordquery(const string& s) :query_word(s){}
/*************重新定义查询方式eval和查询的文本rep()*********************************/
QueryResult eval(const Textquery& t)const override{return t.query(query_word); };
/***************eval2直接继承************************************/
string rep()const override{ return query_word; };
string query_word;
};
/********定义Query构造函数函数********************/
Query::Query(const string& s) : q(make_shared<Wordquery>(Wordquery(s))){}
/********定义Notquery*********************************************/
class Notquery : public Query_base
{
friend Query operator~(const Query&);
/*********构造函数********************/
Notquery(const Query&q) :query(q){}
/*************重新定义查询方式eval和查询的文本rep()*********************************/
QueryResult eval(const Textquery& t)const override;
string rep()const override { return "~("+ query.rep() + ")"; };
Query query;
};
/****************重载operator~**********************/
Query operator~(const Query&q)
{
return shared_ptr<Query_base>(new Notquery(q));
}
QueryResult Notquery::eval(const Textquery& t)const
{
auto result = query.eval(t);
auto ret_lines = make_shared<set<size_t>>();
auto beg = result.begin(), end = result.end();
for (size_t n = 1; n != result.get_file()->size()+1; ++n)
{
if (beg == end || (*beg) != n)
ret_lines->insert(n);
else if (beg != end)
++beg;
}
return QueryResult(rep(), result.get_file(), ret_lines);
}
/*****************定义BinaryQuery:抽象基类****************************/
class BinaryQuery : public Query_base
{
protected:
BinaryQuery(const Query& lhs, const Query& rhs, string s) :
query1(lhs), query2(rhs), opsym(s){}
string opsym;
Query query1, query2;
/*************覆盖继承而来的虚函数***************************/
string rep()const override { return "( "+ query1.rep() +" "+ opsym+query2.rep()+" "+" )"; };
/**************不定义eval,因此它还是一个纯虚函数******************************/
};
/*************定义Addquery*********************/
class Addquery :public BinaryQuery
{
friend Query operator&(const Query&, const Query&);
/****************利用抽象基类的构造函数初始化类的对象**************************/
Addquery(const Query& lhs, const Query& rhs) :BinaryQuery(lhs, rhs, "&"){}
/****************覆盖相应的纯虚函数************************/
QueryResult eval(const Textquery&)const override;
};
/*************重载符号函数&************/
Query operator&(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new Addquery(lhs, rhs));
}
QueryResult Addquery::eval(const Textquery& t)const
{
auto lhs_result = query1.eval(t), rhs_result = query2.eval(t);
auto ret_lines = make_shared<set<size_t>>();
set_intersection(lhs_result.begin(), lhs_result.end(), rhs_result.begin(),
rhs_result.end(), inserter(*ret_lines,ret_lines->begin()));
return QueryResult(rep(), lhs_result.get_file(), ret_lines);
}
/*************定义Orquery*********************/
class Orquery :public BinaryQuery
{
friend Query operator|(const Query&, const Query&);
/****************利用抽象基类的构造函数初始化类的对象**************************/
Orquery(const Query& lhs, const Query& rhs) :BinaryQuery(lhs, rhs, "|"){}
/****************覆盖相应的纯虚函数************************/
QueryResult eval(const Textquery&)const override;
};
/*************重载符号函数|************/
Query operator|(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new Orquery(lhs, rhs));
}
QueryResult Orquery::eval(const Textquery& t)const
{
auto lhs_result = query1.eval(t), rhs_result = query2.eval(t);
auto ret_lines = make_shared<set<size_t>>(lhs_result.begin(), lhs_result.end());
ret_lines->insert(rhs_result.begin(), rhs_result.end());
return QueryResult(rep(), lhs_result.get_file(), ret_lines);
}
#endif
#include "Query_base_derived.h"
#include "iterator"
#include "vector"
using namespace std;
int main()
{
Textquery t("Text.txt");
auto q = Query("hair")|Query("bird");
q.add_history();
auto p = ~Query("fiery");
p.add_history();
auto q2 = history_query(2)&history_query(1);
print(cout, q2.eval(t,3,8));
return 0;
}