C++ Primer 学习笔记_74_面向对象编程 -再谈文本查询示范[续/习题]

面向对象编程

--再谈文本查询示例[续/习题]

//P522 习题15.41
//1 in TextQuery.h
#ifndef TEXTQUERY_H_INCLUDED
#define TEXTQUERY_H_INCLUDED

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <stdexcept>

using namespace std;

class TextQuery
{
public:
    typedef std::vector<std::string>::size_type line_no;
    typedef string::size_type str_size;

    void read_file(std::ifstream &is)
    {
        store_file(is);
        build_map();
    }

    std::set<line_no> run_query(const std::string &) const;
    std::string text_line(line_no) const;

    line_no size() const;

private:
    void store_file(std::ifstream &);
    void build_map();

    std::vector<std::string> line_of_text;
    std::map< std::string,std::set<line_no> > word_map;
};

#endif // TEXTQUERY_H_INCLUDED
//2 in TextQuery.cpp
#include "TextQuery.h"

void TextQuery::store_file(ifstream &is)
{
    string textline;
    while (getline(is,textline))
    {
        line_of_text.push_back(textline);
    }
}

void TextQuery::build_map()
{
    for (line_no line_num = 0;
            line_num != line_of_text.size();
            ++line_num)
    {
        istringstream line(line_of_text[line_num]);
        string word;

        while (line >> word)
        {
            word_map[word].insert(line_num);
        }
    }
}

set<TextQuery::line_no>
TextQuery::run_query(const std::string &query_word) const
{
    map<string,set<line_no> >::const_iterator loc =
        word_map.find(query_word);

    if (loc == word_map.end())
    {
        return set<TextQuery::line_no>();
    }
    else
    {
        return loc -> second;
    }
}

string TextQuery::text_line(line_no line) const
{
    if (line < line_of_text.size())
    {
        return line_of_text[line];
    }
    throw out_of_range("line number out of range");
}

TextQuery::str_size TextQuery::size() const
{
    return line_of_text.size();
}
//3 in Query.h
#ifndef QUERY_H_INCLUDED
#define QUERY_H_INCLUDED

#include "TextQuery.h"
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

class Query_base
{
    friend class Query;

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

private:
    virtual set<line_no> eval(const TextQuery &) const = 0;
    virtual ostream &display(ostream & = cout) const = 0;
};

class Query
{
    friend Query operator~(const Query &);
    friend Query operator|(const Query &,const Query &);
    friend Query operator&(const Query &,const Query &);

public:
    Query(const string &);

    Query(const Query &c):p(c.p),use(c.use)
    {
        ++ *use;
    }
    ~Query()
    {
        decr_use();
    }
    Query &operator=(const Query &);

    set<TextQuery::line_no>
    eval(const TextQuery &t) const
    {
        return p -> eval(t);
    }

    ostream &display(ostream &os) const
    {
        return p -> display(os);
    }

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

    Query_base *p;
    std::size_t *use;

    void decr_use()
    {
        if ( -- *use == 0 )
        {
            delete p;
            delete use;
        }
    }
};

inline Query &
Query::operator=(const Query &rhs)
{
    ++ * rhs.use;
    decr_use();

    p = rhs.p;
    use = rhs.use;

    return *this;
}

inline ostream &
operator<<(ostream &os,const Query &q)
{
    return q.display(os);
}

class WordQuery : public Query_base
{
    friend class Query;

    WordQuery(const string &s):query_word(s) {}

    set<line_no> eval(const TextQuery &t) const
    {
        return t.run_query(query_word);
    }
    ostream &display(ostream &os) const
    {
        return os << query_word;
    }

    string query_word;
};

inline Query::Query(const string &s):
    p(new WordQuery(s)),use(new std::size_t(1)) {}

class NotQuery : public Query_base
{
    friend Query operator~(const Query &);
    NotQuery(Query q):query(q) {}

    set<line_no> eval(const TextQuery &) const;

    ostream &display(ostream &os) const
    {
        return os << "~(" << query << ")";
    }

    const Query query;
};

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

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

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

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

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

    set<line_no> eval(const TextQuery &) const;
};

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

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

    set<line_no> eval(const TextQuery &) const;
};

inline Query
operator&(const Query &lhs,const Query &rhs)
{
    return new AndQuery(lhs,rhs);
}

inline Query
operator|(const Query &lhs,const Query &rhs)
{
    return new OrQuery(lhs,rhs);
}

inline Query
operator~(const Query &oper)
{
    return new NotQuery(oper);
}

#endif // QUERY_H_INCLUDED
//4 in Query.cpp
#include "Query.h"

set<TextQuery::line_no>
OrQuery::eval(const TextQuery &file) const
{
    set<line_no> left = lhs.eval(file),
                 ret_lines = rhs.eval(file);

    ret_lines.insert(left.begin(),left.end());

    return ret_lines;
}

set<TextQuery::line_no>
AndQuery::eval(const TextQuery &file) const
{
    set<line_no> left = lhs.eval(file),
    right = rhs.eval(file);

    set<line_no> ret_lines;
    set_intersection(left.begin(),left.end(),
                     right.begin(),right.end(),
                     inserter(ret_lines,ret_lines.begin()));

    return ret_lines;
}

set<TextQuery::line_no>
NotQuery::eval(const TextQuery &file) const
{
    set<line_no> hav_val = query.eval(file);
    set<line_no> ret_val;

    for (line_no n = 0; n != file.size(); ++n)
    {
        if (hav_val.find(n) == hav_val.end())
        {
            ret_val.insert(n);
        }
    }

    return ret_val;
}
//5 in main.cpp
//测试数据与前面相同
#include <iostream>
#include <algorithm>
#include "TextQuery.h"
#include "Query.h"

using namespace std;

int main()
{
    ifstream inFile("input");

    TextQuery file;
    file.read_file(inFile);

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

    cout << "Executed Query for :" << q << endl;

    typedef set<TextQuery::line_no> line_nums;

    const line_nums &locs = q.eval(file);

    cout << "match occurs " << locs.size()
         << " times" << endl;

    line_nums::const_iterator it = locs.begin();
    for (; it != locs.end(); ++it)
    {
        cout << "\t(line " << (*it) + 1 << ") "
             << file.text_line(*it) << endl;
    }
}

运行示例:

时间: 2024-11-04 08:43:35

C++ Primer 学习笔记_74_面向对象编程 -再谈文本查询示范[续/习题]的相关文章

C++ Primer 学习笔记_74_面向对象编程 --再谈文本查询示例[续/习题]

面向对象编程 --再谈文本查询示例[续/习题] //P522 习题15.41 //1 in TextQuery.h #ifndef TEXTQUERY_H_INCLUDED #define TEXTQUERY_H_INCLUDED #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <set> #include <map&g

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

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

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

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_66_面向对象编程 --定义基类和派生类[续]

算法旨在用尽可能简单的思路解决问题,理解算法也应该是一个越看越简单的过程,当你看到算法里的一串概念,或者一大坨代码,第一感觉是复杂,此时不妨从例子入手,通过一个简单的例子,并编程实现,这个过程其实就可以理解清楚算法里的最重要的思想,之后扩展,对算法的引理或者更复杂的情况,对算法进行改进.最后,再考虑时间和空间复杂度的问题. 了解这个算法是源于在Network Alignment问题中,图论算法用得比较多,而对于alignment,特别是pairwise alignment, 又经常遇到maxim

C++ Primer 学习笔记33_面向对象编程(4)--虚函数与多态(一):多态、派生类重定义、虚函数的访问、 . 和-&gt;的区别、虚析构函数、object slicing与虚函数

C++ Primer学习笔记33_面向对象编程(4)--虚函数与多态(一):多态.派生类重定义.虚函数的访问. . 和->的区别.虚析构函数.object slicing与虚函数 一.多态 多态可以简单地概括为"一个接口,多种方法",前面讲过的重载就是一种简单的多态,一个函数名(调用接口)对应着几个不同的函数原型(方法). 更通俗的说,多态行是指同一个操作作用于不同的对象就会产生不同的响应.或者说,多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态行分

C++ Primer 学习笔记_67_面向对象编程 --转换与继承、复制控制与继承

面向对象编程 --转换与继承.复制控制与继承 I.转换与继承 引言: 由于每一个派生类对象都包括一个基类部分,因此能够像使用基类对象一样在派生类对象上执行操作. 对于指针/引用,能够将派生类对象的指针/引用转换为基类子对象的指针/引用. 基类类型对象既能够作为独立对象存在,也能够作为派生类对象的一部分而存在,因此,一个基类对象可能是也可能不是一个派生类对象的部分,因此,没有从基类引用(或基类指针)到派生类引用(或派生类指针)的(自己主动)转换. 关于对象类型,尽管一般能够使用派生类型的对象对基类

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数、抽象类、虚析构函数、动态创建对象

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数.抽象类.虚析构函数.动态创建对象 一.纯虚函数 1.虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 2.如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 3.在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 4.定义纯虚函数: class <类名> { virtual <类型> <函

C++ Primer 学习笔记_65_面向对象编程 --概述、定义基类和派生类

面向对象编程 --概述.定义基类和派生类 引言: 面向对象编程基于的三个基本概念:数据抽象.继承和动态绑定. 在C++中,用类进行数据抽象,用类派生从一个类继承另一个:派生类继承基类的成员.动态绑定使编译器能够在运行时决定是使用基类中定义的函数还是派生类中定义的函数. 继承和动态绑定在两个方面简化了我们的程序:[继承]能够容易地定义与其他类相似但又不相同的新类,[派生]能够更容易地编写忽略这些相似类型之间区别的程序. 面向对象编程:概述 面向对象编程的关键思想是多态性(polymorphism)