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

2014-11-24 12:57:15 · 作者: · 浏览: 2
ales_item句柄一样,Query句柄将保存指向继承层次中一个类型的对象的指针,Query类还指向一个使用计数,我们用这个使用计数管理句柄指向的对象。

在这种情况下,句柄将完全屏蔽基础继承层次,用户将只能间接地通过Query对象的操作创建和操纵Query_base对象。我们将定义Query对象的三个重载操作符以及Query构造函数,Query构造函数将动态分配新的Query_base对象。每个操作符将生成的对象绑定到Query句柄

1)&操作符将生成绑定到新的AndQuery对象的 Query对象;

2)|操作符将生成绑定到新的OrQuery对象的 Query对象;

3)~操作符将生成绑定到新的NotQuery对象的 Query对象。

4)给Query定义一个参数为string对象的构造函数,该构造函数将生成新的WordQuery

Query类将提供与Query_base类同样的操作:eva l 对相关查询进行计算,display 打印查询。它将定义重载输出操作符显示相关查询。

查询程序设计:扼要重述

操作或表达式

功能

TextQuery

读指定文件并创建相关查找映射的类。该类提供query_text操作,该操作接受string实参并返回一个set,保存出现实参的行的编号

Query_base

查询类的抽象基类

Query

用于计数的句柄类,它指向Query_base派生类的对象

WordQuery

从Query_base派生的类,查找给定单词

NotQuery

从Query_base派生的类,返回操作数不出现的行的编号的集合

BinaryQuery

从Query_base派生的抽象基类类型,表示带两个Query操作数的查询

OrQuery

从BinaryQuery派生的类,返回两个操作数出现的行编号集的并集

AndQuery

从BinaryQuery派生的类,返回两个操作数出现的行编号集的交集

q1& q2

返回Query对象,该Query对象绑定到保存q1和q2的新AndQuery对象

q1| q2

返回Query对象,该Query对象绑定到保存q1和q2的新OrQuery对象

~q

返回Query对象,该Query对象绑定到保存q的新NotQuery对象

Queryq(s)

将Queryq绑定到保存strings的新的WordQuery对象



我们的设计:扼要重述

【小心地雷】

理解设计经常是最困难的部分,尤其是刚开始设计面向对象系统时。一旦熟悉了设计,实现就是顺理成章的了

这个应用程序的主要工作由建立对象表示用户的查询构成,认识到这一点很重要。如下图所示,表达式:

	Query q = Query("fiery") & Query("bird") | Query("wind");

生成10个对象:5个Query_base对象及其相关联的句柄。5个Query_base对象分别为:3个WordQuery对象,一个OrQuery对象和AndQuery对象。

\
一旦建立了对象树,计算(或显示)给定查询基本上就是沿着这些链接,要求树中每个对象计算(或显示)自己的过程,该过程由编译器管理。
例如,如果调用 q (即,在这棵树的树根)的eva l,则 eva l 将要求 q 指向的 OrQuery 对 象调用 eva l 来计算自己,计算这个 OrQuery对象用两个操作数调用 eva l,这个依次调用 AndQuery 对象和 WordQuery 对象的 eva l,查找单词 wind,依此 类推。


三、Query_base类
首先定义Query_base类:

class Query_base
{
    friend class Query;
protected:
    typedef TextQuery::line_no line_no;
    virtual ~Query_base() {}

private:
    virtual std::set
  
   
    eva l(const TextQuery &) const = 0;

    virtual std::ostream &
    display(std::ostream & = std::cout) const = 0;
};

  


这个类定义了两个接口成员:eva l和display。两个成员都是纯虚函数,因此该类为抽象类,应用程序中将没有Query_base类型的对象。

用户和派生类将只通过Query句柄使用Query_base类,因此,将Query_base接口设为private。(虚)析构函数和类型别名为 protected,这些派生类型就能够访问这些成员,构造函数由派生类构造函数(隐式)使用,因此派生类必须能够访问构造函数

给Query句柄类授予友元关系,该类的成员将调用Query_base中的虚函数因此必须能够访问它们。



四、Query句柄类

Query句柄将类似于Sales_item类,因为它将保存Query_base指针和使用计数指针。像Sales_item类一样,Query的复制控制成员将管理使用计数和Query_base指针。

与Sales_item不同的是,Query类将只为Query_base继承层次提供接口。用户将不能直接访问Query或其派生类的任意成员。这一设计决定导致Query和 Sales_item之间存在两个区别:

第一个区别是,Query类将不定义解引用操作符和箭头操作符的重载版本。Query_base类没有 public成员,如果Query句柄定义了解引用操作符和箭头操作符,它们将没有用处!使用那些操作符访问成员的任何尝试都将失败,相反,Query类必须定义接口函数eva ldisplay的自身版本。

另一个区别来自于我们打算怎样创建继承层次的对象。我们的设计指出将只通过 Query句柄的操作创建Query_base的派生类对象,这个区别导致Query类需要与Sales_item句柄中所用的构造函数不同的构造函数。



1、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 &);
    Query(const Query &c):q(c.q),use(c.use)
    {
        ++ *use;
    }

    ~Query()
    {
        desr_use();
    }

    Query &operator=(const Query &);

    std::set
  
    eva l(const TextQuery &t) const
    {
        return q -> eva l(t);
    }

    std::ostream &display(std::ostream &os = std::cout)
    {
        return q -> display(os);
    }

private:
    Query(Query_base *query):q(query),use(new std::size_t(1)) {}

    Query_base *q;
    std::size_t *use;

    void de