c++ 派生类 文本查询程序再探

Query_base类和Query类

cpp 复制代码
//这是一个抽象基类,具体的查询类型从中派生,所有成员都是private的
class Query_base {
    friend class Query;
    protected:
    using line_no = TextQuery::line_no;//用于level函数
    virtual ~Query_base() = default;
    private:
    //eval返回与当前Query匹配的QueryResult
    virtual QueryResult eval(const TextQuery&) const = 0;
    //rep是表示查询 的一个string
    virtual std::string rep() const = 0;
};

//这是一个管理Query_base继承体系的接口类
class Query{
    //这些运算符需要访问接受shared_ptr的构造函数,而该函数是私有的
    friend Query operator~(const Query &);
    friend Query operator|(const Query&,const Query&);
    friend Query operator&(const Query&,const Query&);
    public:
    Query(const std::string&);//构建一个新的WordQuery
    //接口函数:调用对应的Query_base操作
    QueryResult eval(const TextQuery &t) const
    {return q->eval(t);}
    std::string rep() const {return q->req();}

    private:
    Query(std::shared_ptr<Query_base> query):q(query){  }
    std::shared_ptr<Query_base> q;
};

Query的输出运算符

cpp 复制代码
std::ostream & 
operator<<(std::ostream &os,const Query &query)
{
    //Query::rep通过它的Query_base指针对rep()进行虚调用
    return os<<query.rep();
}

Query andq = Query(sought1) & Query(sought2);
cout<<andq<<endl;

派生类

cpp 复制代码
class WordQuery: public Query_base {
    friend class Query; //Query使用WordQuery构造函数
    WordQuery(const std::string &s) : query_word(s) { }
    //具体的类:WordQuery将定义所有继承而来的纯虚函数
    QueryResult eval(const TextQuery &t) const
        {return t.query(query_word);}
    std::string rep() const {return query_word;}
    std::string query_word; //要查找的单词
};

NotQuery类及 ~运算符

cpp 复制代码
class NotQuery : public Query_base {
    friend Query operator~(const Query &);
    NotQuery(const Query &q):query(q){ }
    //具体的类:NotQuery将定义所有继承而来的纯虚函数
    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(oprand));
}

//分配一个新的NotQuery对象
//将所得的NotQuery指针绑定到一个shared_ptr<Query_base>
shared_ptr<Query_base> tmp(new NotQuery(expr));
return Query(tmp);  //使用接受一个shared_ptr的Query构造函数

BinaryQuery类

cpp 复制代码
class BinaryQuery : public Query_base{
    protected:
    BinaryQuery(const Query &l,const Query &r,std::string s):
        lhs(l),rhs(r),opSym(s){ }
    //抽象类:BinaryQuery不定义eval
    std::string rep() const { return "(" + lhs.rep() + " " 
    +opSym + ""  
    +rhs.rep() + ")";}
    Query lhs,rhs;  //左侧和右侧运算符对象

    std::string opSym;  //运算符名字
};

AndQuery类、OrQuery类及相应的运算符

cpp 复制代码
    class AndQuery : public BinaryQuery {
        friend Query operator&(const Query&,const Query&);
        AndQuery(const Query &left,const Query &right) : 
            BinaryQuery(left,right,"&"){ }
            //具体的类: AndQuery继承了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,"|"){ }
        QueryResult eval(const TextQuery&)const;
    };
    inline Query operator|(const Query &lhs,const Query &rhs)
    {
        return std::shared_ptr<Query_base>(new OrQuery(lhs,rhs));
    }

eval函数

cpp 复制代码
//返回运算对象查询结果set的并集
OrQuery::eval(const TextQuery& text) const
{
    //通过Query成员lhs和rhs进行的虚调用
    //调用eval返回每个运算对象的QueryResult
    auto right = rhs.eval(text),left = lhs.eval(text);
    //将左侧运算对象的行号拷贝到结果set中
    auto ret_lines =
        make_shared<set<line_no>>(left.begin(),left.end());

    //插入右侧运算对象所得的行号
    ret_lines->insert(right.begin(),right.end());
    //返回一个新的QueryResult,它表示lhs和rhs的并集
    return QueryResult(rep(),ret_lines,left.get_file());
}

//返回运算对象查询结果set的交集
QueryResult
AndQuery::eval(const TextQuery& text) const
{
    //通过Query运算对象进行的虚调用,以获得运算对象的查询结果set
    auto left = lhs.eval(text),right = rhs.eval(text);
    //保存left 和 right交集的set
    auto ret_lines =  make_shared<set<line_no>>();
    //将两个范围的交集写入一个目的迭代器中
    //本次调用的目的迭代器向ret添加元素
    set_intersection(left.begin(),left.end(),
            right.begin(),right.end(),
            inserter(*ret_lines,ret_lines->begin()));
    return QueryResult(rep(),ret_lines,left.get_file());
}

//返回运算对象的结果set中不存在的行
QueryResult
NotQuery::eval(const TextQuery& text) const
{
    //通过Query运算对象对eval进行虚调用
    auto result = query.eval(text);
    //开始时结果set为空
    auto ret_lines = make_shared<set<line_no>>();
    //我们必须在运算对象出现的所有行中进行迭代
    auto beg = result.begin(),end = result.end();
    //对于输入文件的每一行,如果该行不在result当中,则将其添加到ret_lines
    auto sz = result.get_file()->size();
    for(size_t n = 0;n != sz; ++n){
        //如果我们还没有处理完result的所有行
        //检查当前行是否存在
        if(beg = end || *beg != n)
            ret_lines->insert(n);   //如果不在result当中,添加这一行
        else if(beg != end)
            ++beg;  //否则继续获取result的下一行(如果有的话)
    }
    return QueryResult(rep(),ret_lines,result.get_file());
}
相关推荐
似霰2 分钟前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
芊寻(嵌入式)13 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
獨枭14 分钟前
C++ 项目中使用 .dll 和 .def 文件的操作指南
c++
霁月风17 分钟前
设计模式——观察者模式
c++·观察者模式·设计模式
橘色的喵18 分钟前
C++编程:避免因编译优化引发的多线程死锁问题
c++·多线程·memory·死锁·内存屏障·内存栅栏·memory barrier
MonkeyKing_sunyuhua34 分钟前
ubuntu22.04 docker-compose安装postgresql数据库
数据库·docker·postgresql
天郁青34 分钟前
数据库交互的本地项目:后台管理系统
数据库·交互
马剑威(威哥爱编程)39 分钟前
MongoDB面试专题33道解析
数据库·mongodb·面试
何曾参静谧1 小时前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++
AI街潜水的八角1 小时前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习