//是一个抽象基类,具体的查询类型从中派生
//不希望用户或者派生类直接使用Query_base,而是通过Query,所有成员都是private的
class Query_base {
friend class Query; //Query需要调用Query_base的虚函数,声明为友元
protected:
using line_no = TextQuery::line_no; //用于eval函数
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继承体系的接口类
//Query类对外提供接口,同时隐藏了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:
//构建一个新的WordQuery
Query(const std::string& s) : q(new WordQuery(s)) {}
//接口函数:调用对应的Query_base操作
Query_base eval(const TextQuery& t) const {
return q->eval(t);
}
std::string rep() const {
return q->rep();
}
std::ostream& operator<<(std::ostream& os, const Query& query) {
//Query::rep通过它的Query_base指针对rep()进行了虚调用
return os << query.rep();
}
private:
//私有的,不希望一般的用户代码能随便定义Query_base对象
Query(std::shared_ptr<Query_base> query) : q(query) {}
std::shared_ptr<Query_base> q;
};
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; //要查找的单词
};
//直接使用一个Query对象,就像用户代码可以通过接口类得到简化一样,直接用接口类简化自己的类
class NotQuery : public Query_base {
//成员私有,设置成友元
friend Query operator~(const Query& operand) {
//隐式地使用接受一个shared_ptr<Query_base>的Query构造函数
return std::shared_ptr<Query_base>(new NotQuery(operand));
}
NotQuery(const Query& q) : query(q) {}
//具体的类:NotQuery将定义所有继承而来的纯虚函数
std::string rep() const {
return "~(" + query.rep() + ")"; //最终执行的为虚调用
}
QueryResult eval(const TextQuery&) const;
Query query;
};
//没有定义eval,而是继承该虚函数,因此也是一个抽象基类
class BinaryQuery : public Query_base {
protected:
BinaryQuery(const Query& l, const Query& r, std::string s) :
lhs(l), rhs(r), opSym(s) {}
std::string rep() const {
return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
}
Query lhs, rhs; //左侧和右侧运算对象
std::string opSym; //运算符名字
};
//将运算符定义为友元
//构造函数通过运算符创建BinaryQuery基类部分
class AndQuery : public BinaryQuery {
friend Query operator&(const Query& lhs, const Query& rhs) {
return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
AndQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "&") {}
QueryResult eval(const TextQuery&) const;
};
class OrQuery : public BinaryQuery {
friend Query operator|(const Query& lhs, const Query& rhs) {
return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
OrQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "|") {}
QueryResult eval(const TextQuery&) const;
};
//eval函数是我们这个查询系统的核心。每个eval 函数作用于各自的运算对象,同时遵循的内在逻辑也有所区别
QueryResult OrQuery::eval(const TextQuery& text) const {
//通过Query成员lhs和rhs进行的虚调用
//调用veal返回每个运算对象的QueryResult
auto right = rhs.eval(test), left = lhs.eval(text);
//将左侧运算对象的行号拷贝到结果set中
auto ret_lines = std::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());//right和left指向的是同一文件
}