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 分钟前
MySQL中的锁有哪些
数据库·mysql
cts6183 分钟前
Milvus分布式数据库工作职责
数据库·分布式·milvus
周胡杰3 分钟前
鸿蒙加载预置数据库-关系型数据库-如何读取本地/预制数据库
数据库·华为·harmonyos·鸿蒙
布朗克1687 分钟前
java常见的jvm内存分析工具
java·jvm·数据库
胡八一14 分钟前
SQLite / LiteDB 单文件数据库为何“清空表后仍占几 GB”?——原理解析与空间回收实战
jvm·数据库·sqlite
2401_831501731 小时前
Linux之Zabbix分布式监控篇(二)
数据库·分布式·zabbix
秋林辉2 小时前
Jfinal+SQLite处理 sqlite数据库执行FIND_IN_SET报错
jvm·数据库·sqlite
古月-一个C++方向的小白5 小时前
C++11之lambda表达式与包装器
开发语言·c++
巴里巴气6 小时前
MongoDB复杂查询 聚合框架
数据库·mongodb
tanyongxi667 小时前
C++ AVL树实现详解:平衡二叉搜索树的原理与代码实现
开发语言·c++