C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例(三)

2014-11-24 12:57:15 · 作者: · 浏览: 9
Query两个查询类型所需的数据,AndQuery和OrQuery有两个操作数:

class BinaryQuery : public Query_base
{
protected:
    BinaryQuery(Query left,Query right,std::string &op):
        lhs(left),rhs(right),oper(op) {}

    std::ostream &
    display(std::ostream &os) const
    {
        return os << "(" << lhs << " " << oper
               << " " << rhs << ")";
    }

    const Query lhs,rhs;
    const std::string oper;
};

BinaryQuery中的数据是两个Query操作数,以及显示查询时使用的操作符符号。这些数据均声明为const,因为一旦建立了查询的内容就不应该再改变。构造函数接受两个操作数以及操作符符号,将它们存储在适当的数据成员中。

要显示一个BinaryOperator对象,打印由圆括号括住的表达式、该表达式由左操作数后接操作、再接右操作数构成。像显示NotQuery对象一样,用于打印left和 right的重载 <<操作符最终对基础Query_base对象的display进行虚函数调用。

【注解】

BinaryQuery类没有定义eva l函数,因此继承了一个纯虚函数。这样,BinaryQuery也是一个抽象类,不能创建BinaryQuery类型的对象。



4、AndQuery和OrQuery类

AndQuery类和 OrQuery类几乎完全相同:

class AndQuery : public BinaryQuery
{
    friend Query operator&(const Query &,const Query &);

    AndQuery(const Query left,const Query right):
        BinaryQuery(left,right,"&") {}

    std::set
  
    eva l(const TextQuery &) const;
};
class OrQuery : public BinaryQuery
{
    friend Query operator|(const Query &,const Query &);

    OrQuery(const Query left,const Query right):
        BinaryQuery(left,right,"|"){}

    std::set
   
     eva l(const TextQuery &) const; };
   
  

这两个类将各自的操作符设为友元,并定义了构造函数用适当的操作符创建它们的BinaryQuery基类部分它们继承BinaryQuery类的display函数定义,各自定义了自己的eva l函数版本



六、eva l函数

查询类层次的中心是虚函数eva l每个eva l函数调用其操作数的eva l函数,然后应用自己的逻辑:AndQuery的 eva l操作返回两个操作数的结果的并集,OrQuery的 eva l操作返回交集,NotQuery的 eva l操作比较复杂:它必须返回不在其操作数的集合中的行编号。



1、OrQuery::eva l

OrQuery对象合并由它的两个操作数返回的行号编号集合―― 其结果是它的两个操作数的结果的并集:

set
  
   
OrQuery::eva l(const TextQuery &file) const
{
    set
   
     right = rhs.eva l(file), ret_lines = lhs.eva l(file); ret_lines.insert(right.begin(),right.end()); return ret_lines; } 
   
  

eva l函数首先调用每个操作数的eva l函数,操作数的eva l函数调用Query::eva l,Query::eva l再调用基础Query_base对象的虚函数eva l,每个调用获得其操作数出现在其中表示对右操作数求值所返回的set。因为ret_lines是一个 set对象,这个调用将right中未在left中出现的元素加到ret_lines中。调用insert函数之后,ret_lines包含在 left集或在right集的每个行编号。返回ret_lines而结束OrQuery::eva l函数。



2、AndQuery::eva l

set
  
   
AndQuery::eva l(const TextQuery &file) const
{
    set
   
     left = lhs.eva l(file), right = rhs.eva l(file); set
    
      ret_linies; //该标准库算法的简单介绍可以在附录A.2.8节找到 set_intersection(left.begin(),left.end(), right.begin(),right.end(), inserter(ret_linies,ret_linies.begin())); return ret_linies; } 
    
   
  

eva l函数这个版本使用set_intersection算法查找两个查询中的公共行:该算法接受5个迭代器,前4个表示两个输入范围,最后一个表示目的地。算法将同时在两个输入范围中存在的每个元素写到目的地。该调用的目的地是一个迭代器,它将新元素插入到ret_lines中。



3、NotQuery::eva l

NotQuery查找未出现操作数的每个文本行。要支持这个函数,需要TextQuery类增加一个成员返回文件的大小size,以便了解存在什么样的行编号。

set
  
   
NotQuery::eva l(const TextQuery &file) const
{
    set
   
     has_val = query.eva l(file); set
    
      ret_lines; for (TextQuery::line_no n = 0;n != file.size(); ++n) { if (has_val.find(n) == has_val.end()) { ret_lines.insert(n); } } return ret_lines; }
    
   
  

像其他eva l函数一样,首先调用该对象的操作数的eva l函数。该调用返回操作数所出现的行编号的set,而我们想要的是不出现操作数的行编号的set,通过查找输入文件的每个行编号获得该set。使用必须加到TextQuery的size成员控制 for循环,该循环将没有在has_val中出现的每个行编号加到ret_lines中,一旦处理完所有的行编号,就返回ret_lines。