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());
}
相关推荐
煤泥做不到的!1 小时前
挑战一个月基本掌握C++(第十一天)进阶文件,异常处理,动态内存
开发语言·c++
F-2H1 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
Minxinbb1 小时前
MySQL中Performance Schema库的详解(上)
数据库·mysql·dba
axxy20001 小时前
leetcode之hot100---24两两交换链表中的节点(C++)
c++·leetcode·链表
mmsx2 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
若亦_Royi2 小时前
C++ 的大括号的用法合集
开发语言·c++
zpjing~.~3 小时前
Mongo 分页判断是否有下一页
数据库
2401_857600953 小时前
技术与教育的融合:构建现代成绩管理系统
数据库·oracle
秋恬意4 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
潇湘秦4 小时前
一文了解Oracle数据库如何连接(1)
数据库·oracle