我对编程还很陌生,因此请回答是否显而易见的问题。
Lippman,Lajoie和Moo撰写的C ++ Primer(第5版)的15.9节中,涉及编程继承层次结构。它基本上是一个抽象类Query_base
,其子类是WordQuery
,NotQuery
和BinaryQuery
,最后一个子类进一步分支到AndQuery
和OrQuery
。 Query_base
层次结构由称为Query
的接口类通过指针访问。此设置背后的基本思想是使用复合查询,例如:Query q = Query("fiery") & Query("bird") | Query("wind")
(这些运算符生成指向Query
类型对象的Query_base
对象,例如,'&
'生成AndQuery
,'~
'生成NotQuery
。
然后可以在文本文档中搜索符合查询规则的行。)
Query_base类如下:
class Query_base {
friend class Query;
protected:
virtual ~Query_base() = default;
private:
virtual QueryResult eval(const TextQuery&) const = 0;
virtual std::string rep() const = 0;
}
所有Query_base子级都实现eval()和rep(),因此可以实例化。
Query类的设计如下:
class Query {
friend Query operator~(const Query&);
friend Query operator|(const Query&, const Query&);
friend Query operator&(const Query&, const Query&);
public:
Query(const std::string&);
QueryResult eval(const TextQuery &t) const { return q->eval(t); }
std::string rep() const { return q->rep(); }
private:
Query(std::shared_ptr<Query_base> query) : q(query) { }
std::shared_ptr<Query_base> q;
因此,我的理解是该设计具有继承层次结构,然后有一个故意分离的接口。后者照原样从侧面访问前者,而不仅仅是让基类充当接口。
我有两个问题:
没有单独的
Query
类有什么问题吗?我们能否仅将Query_base
类用作层次结构和接口的基础,并摆脱Query
类?我认识到Query_base
不能,因为它具有纯虚函数,但是可以更改。例如,我不能仅将Query
和eval()
的rep()
函数实现移到Query_base
吗?这样做有什么问题吗? shared_ptr<Query_base>
中的Query
是否会使事情复杂化并且是分离的基础,如果是,我们是否可以解决该问题?像这样的层次结构接口分离有多普遍(如果这是思考这一问题的正确方法)?
提前致谢!
最佳答案
如果我们继续实现所有这些运算符和其他子查询类型,则分离的需求变得很明显。让我们想象一下&运算符的外观。&
运算符应构造一个查询,该查询又应包含其他两个查询。
因此,可以这样定义AndQuery
类:
class AndQuery: public BinaryQuery {
public:
AndQuery(const Query_base& lhs, const Query_base& rhs);
AndQuery(Query_base&& lhs, Query_base&& rhs);
...
QueryResult eval(const TextQuery& t) override;
private:
// required members and private methods...
// two principal members, lhsQuery and rhsQuery for
// left hand side subquery and light hand side subquery
// correspondingly are defined in `BinaryQuery`
};
并且,在一个未经优化的简单情况下,
AndQuery
应该以这种方式执行搜索(eval()
):QueryResult AndQuery::eval(const TextQuery& t) {
QueryResult lhsResult = lhsQuery.eval(t);
QueryResult rhsResult = rhsQeury.eval(t);
// the resulting ResultSet should include only entries
// from both result sets
for(auto it = lhsResult.begin(); it != lhsResult.end(); ++it)
if (rhsResult.find(*it) == rhsResult::cend())
it = lhsResult.erase(it);
// now we can return lhsResult because we have erased all elements from it
// which weren't in rhsResult
return lhsResult;
}
其他查询组件子类具有自己的特定实现。反过来,
Query
有其自己的一组特定方法,例如从字符串构造查询。如果没有纯虚拟的Query_base
,我们必须与所有组件子类共享Query
的实现细节。另外,我们还必须使这些类对外部用户可见。通过使用单独的“ interface”
Query
类,我们为子系统的用户提供了一个清晰易懂的精益接口。