C++primer学习:面向对象程序设计(5):再探文本查询程序

这一节初步探讨了如何设计一个继承类体系。

为我们前面所写的文本探测程序添加以下功能:

(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;//通过该友元访问eval,rep函数
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);//创建一个新的Wordquery类,用来存储查找的单词
    /**********覆盖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)//history不为空&&n是有效的
        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;// q指向某个派生类
};
/****************重载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);//通过Query运算对象进行虚调用
    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)//n不在result里
            ret_lines->insert(n);
        else if (beg != end)// *beg == n
            ++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;
}

C++primer学习:面向对象程序设计(5):再探文本查询程序_第1张图片

你可能感兴趣的:(C++primer学习:面向对象程序设计(5):再探文本查询程序)