c++primer 例子文本程序再探

来源:互联网 发布:ubuntu 12.04 安装jdk 编辑:程序博客网 时间:2024/06/01 08:44

先附上前面的basket类的例子,里面很多思想也是我需要学的

#include <iostream>#include <string>#include <set>#include <memory>//买书的类class quote{    friend double print_total(std::ostream &os, quote &q, std::size_t sz);    public:        quote() = default;        quote(const std::string &book, double p):            bookNo(book), price(p) { }        quote(const quote &q):            bookNo(q.bookNo), price(q.price) { }        quote(quote &&q):             //一个右值拷贝            bookNo(q.bookNo), price(q.price) { }        quote& operator=(const quote &q)        {            bookNo = q.bookNo;            price = q.price;            return *this;        }        virtual double net_price(std::size_t sz)const        {            return price * sz;        }        const std::string& isbn()const        {            return bookNo;        }        //注意动态内存分配问题,基类和派生类的内存大小不同        //所以我们写了个分配函数,且必须定义为虚函数。为了实现后面的动态分配        //后面跟着成员限定符说明是用作左值还是右值        virtual quote* clone()const&        { return new quote(*this); }        virtual quote* clone() &&        { return new quote(std::move(*this)); }    protected:        double price;    private:        std::string bookNo;};double print_total(std::ostream &os, quote &q, std::size_t sz){    double ret = q.net_price(sz);    os << q.isbn() << " " << q.price << " " << ret << "\n";    return ret;}//抽象基类,因为打折有许多不同的措施,但都基于discount和disc_num//简单来说抽象出来一个标准,discount和disc_num 就可以说是一个标准。class disc_quote : public quote{    public:        disc_quote() = default;        disc_quote(const std::string &book, double p, double disc, std::size_t num):            quote(book, p), discount(disc), disc_num(num) { }        double net_price(std::size_t sz)const = 0;   //纯虚函数    protected:        double discount;        std::size_t disc_num;    private:};//第一种打折方式class one_bulk_quote : public disc_quote{    public:        using disc_quote::disc_quote;        double net_price(std::size_t sz)const override        {            if(sz > disc_num)            {                return sz * price * discount;            }            else            {                return sz * price;            }        }        //对第一种打折类实现动态分配        one_bulk_quote* clone()const &        {            return new one_bulk_quote(*this);        }        one_bulk_quote* clone() &&         {            return new one_bulk_quote(std::move(*this));        }    protected:    private:};class two_bulk_quote : public disc_quote{    public:        using disc_quote::disc_quote;        double net_price(std::size_t sz)        {            if(sz > disc_num)            {                return (sz-disc_num) * price * discount + disc_num * price;            }            else            {                return sz * price;            }        }    protected:    private:};class basket{    public:        //void add_item(const std::shared_ptr<quote>&sale)        //{        //    items.insert(sale);        //}        //如果像上面那样写分配内存不会是动态决定的,参数传递是quote,那么无论传参是什么分配都是quote,如果是派生类就会被砍掉一部分。                void add_item(const quote &sale)        {            items.insert(std::shared_ptr<quote>(sale.clone()));        }        void add_item(quote && sale)        {            items.insert(std::shared_ptr<quote>(std::move(sale).clone()));        }        double total_receipt(std::ostream &os)const;    protected:    private:        //自定义比较函数        static bool compare(const std::shared_ptr<quote> &lhs, const std::shared_ptr<quote> &rhs)        {            return lhs->isbn() < rhs->isbn();        }        std::multiset<std::shared_ptr<quote>, decltype(compare)*> items{compare};//decltype不能推断出指针和引用};double basket::total_receipt(std::ostream &os)const{    double sum = 0.0;    //注意下upper_bound的作用    for(auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter))    {        sum += print_total(std::cout, **iter, items.count(*iter));    }    os << "total Sale: " << sum << std::endl;    return sum;}int main(){}




文本程序

#ifndef _TEXTQUERY_H_#define _TEXTQUERY_H_#include <iostream>#include <map>#include <set>#include <fstream>#include <sstream>#include <memory>#include <vector>#include <string>#include <algorithm>class QueryResult;class TextQuery;using line_no = std::vector<std::string>::size_type;class QueryResult{    friend class TextQuery;    friend std::ostream& operator<<(std::ostream &os, const QueryResult &q);    public:        QueryResult() = default;        QueryResult(std::string s, std::shared_ptr<std::set<line_no>>li, std::shared_ptr<std::vector<std::string>>wf):            q_word(s), lines(li), wordfile(wf) { }        std::set<line_no>::iterator begin();        std::set<line_no>::iterator end();        std::shared_ptr<std::vector<std::string>> get_file();    private:        std::string q_word;                                 //要查询单词        std::shared_ptr<std::set<line_no>>lines;            //出现行号        std::shared_ptr<std::vector<std::string>>wordfile;  //单词文件};class TextQuery{    friend class QueryResult;    public:        TextQuery() = default;        TextQuery(std::ifstream &is);        QueryResult query(const std::string &s)const;    private:        std::shared_ptr<std::vector<std::string>>m_file;        std::map<std::string, std::shared_ptr<std::set<line_no>>>m_word_line;     //考虑共享数据的需求    };  //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来使用,隐藏实现class Query{    friend Query operator~(const Query &);    friend Query operator&(const Query &, const Query &);    friend Query operator|(const Query &, const Query &);    friend std::ostream& operator<<(std::ostream &os, const Query &query);    public:        Query(const std::string&);//wait WordQuery        //Query是Query_base的唯一接口,所以必须定义纯虚函数        //且Query就可以通过指针来调用派生类各自Query_base虚函数        QueryResult eval(const TextQuery &t)const        { return q->eval(t); }        std::string rep()const        { return q->rep(); }    private:        //构造函数定义为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;    WordQuery(const std::string &s):query_word(s) { }    //具体的类    QueryResult eval(const TextQuery &t)const    { return t.query(query_word); }    std::string rep()const { return query_word; }    std::string query_word;        //要查找的单词};//无论哪种查询都是建立在WordQuery的根本上,So Query的构造函数用一个WordQuery来初始化inline Query::Query(const std::string &s):    q(new WordQuery(s)) { }class NotQuery: public Query_base{    friend Query operator~(const Query &);    NotQuery(const Query &q):query(q) { }    //具体的类,覆盖掉纯虚函数    std::string rep()const { return "~(" + query.rep() + ")"; }    QueryResult eval(const TextQuery &)const;    Query query;};inline Query operator~(const Query &operand){    //注意返回值    return std::shared_ptr<Query_base>(new NotQuery(operand));}//两个运算符的抽象基类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() + ")"; }    //eval函数没有定义,继承了纯虚函数,还是抽象基类    Query lhs, rhs;    std::string opSym;};class AndQuery: public BinaryQuery{    friend Query operator&(const Query&, const Query&);    AndQuery(const Query &left, const Query &right):        BinaryQuery(left, right, "&") { }    //具体的类,覆盖了eval并且继承了rep    QueryResult eval(const TextQuery&) const;};inline Query operator&(const Query&lhs, const Query&rhs){    return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));}class OrQuery: public BinaryQuery{    friend Query operator|(const Query&, const Query&);    OrQuery(const Query &left, const Query &right):        BinaryQuery(left, right, "|") { }    //具体的类,覆盖了eval并且继承了rep    QueryResult eval(const TextQuery&)const;};inline Query operator|(const Query&lhs, const Query&rhs){    return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));}





#include "textquery.h"std::ostream& operator<<(std::ostream &os, const QueryResult &q){    os << "element occurs:" << q.lines->size() << " times\n";    for(line_no i : *q.lines)    {        os << "   " << "line(" << i+1 << ") ";        os << *(q.wordfile->begin()+i) << "\n";        //os << (*(q.wordfile))[i] << "\n";   //注意运算符优先级    }    return os;}TextQuery::TextQuery(std::ifstream &is):m_file(new std::vector<std::string>){    std::string word;    std::string line;    static int i = 0;    while(std::getline(is, line))    {            //行号        m_file->push_back(line);        i = m_file->size()-1;        std::istringstream ist(line);        while(ist >> word)        {            auto &li = m_word_line[word];  //返回set的shared_ptr            if(!li)                li.reset(new std::set<line_no>);            li->insert(i);        }    }}QueryResult TextQuery::query(const std::string &s)const{    static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);    auto ret = m_word_line.find(s);    if(ret == m_word_line.end())        return QueryResult(s, nodata, m_file);    else        return QueryResult(s, ret->second, m_file);}std::ostream& operator<<(std::ostream &os, const Query &query){    //query.rep()内部还是通过指针来调用的,是需调用    return os << query.rep();}//QueryResultstd::set<line_no>::iterator QueryResult::begin(){    return lines->begin();}std::set<line_no>::iterator QueryResult::end(){    return lines->end();}std::shared_ptr<std::vector<std::string>> QueryResult::get_file(){    return wordfile;}//evalQueryResultOrQuery::eval(const TextQuery &text)const{    auto right = rhs.eval(text), left = lhs.eval(text);    auto ret_lines = std::make_shared<std::set<line_no>>(left.begin(), left.end());    ret_lines->insert(right.begin(), right.end());    return QueryResult(rep(), ret_lines, left.get_file());}QueryResultAndQuery::eval(const TextQuery &text)const{    auto left = lhs.eval(text), right = rhs.eval(text);    auto ret_lines = std::make_shared<std::set<line_no>>();    set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));    return QueryResult(rep(), ret_lines, left.get_file());}QueryResultNotQuery::eval(const TextQuery &text)const{    auto result = query.eval(text);    auto ret_lines = std::make_shared<std::set<line_no>>();    auto beg = result.begin(), end = result.end();    auto sz = result.get_file()->size();    //相当于两个集合两个指针一起走。    for(std::size_t n = 0; n != sz; ++n)    {        if(beg == end || *beg != n)            ret_lines->insert(n);        else if(beg != end)            ++beg;    }    return QueryResult(rep(), ret_lines, result.get_file());}



#include "textquery.h"int main(int argc, char *argv[]){    std::ifstream is(argv[1]);    TextQuery t1(is);    std::string word;    Query q = Query("fiery") & Query("bird") | Query("wind");    //Query q = Query("fiery");    //Query q = Query("A");    std::cout << q << std::endl;    std::cout << q.eval(t1) << std::endl;}

运行结果:


这个例子自己也看了挺久,感觉还是有点复杂,可能是自己写的这种面向对象的不多吧,还要多加联系。

这个例子中的很多思想非常好,值得我们去学习。


总结:

1.好好体会抽象基类纯虚函数这个概念,在c++面向对象编程是非常重要的。

1 0