c++ primer中文版第五版作业第十五章

2024-03-08 22:20

本文主要是介绍c++ primer中文版第五版作业第十五章,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

仓库地址

文章目录

      • 15.1
      • 15.2
      • 15.3
      • 15.4
      • 15.5
      • 15.6
      • 15.7
      • 15.8
      • 15.9
      • 15.10
      • 15.11
      • 15.12
      • 15.13
      • 15.14
      • 15.15
      • 15.16
      • 15.17
      • 15.18
      • 15.19
      • 15.20
      • 15.21
      • 15.22
      • 15.23
      • 15.24
      • 15.25
      • 15.26
      • 15.26
      • 15.28
      • 15.29
      • 15.30
      • 15.31
      • 15.32
      • 15.33
      • 15.34
      • 15.35
      • 15.36
      • 15.37
      • 15.38
      • 15.39
      • 15.40
      • 15.41
      • 15.42

15.1

 基类希望其派生类进行覆盖的函数,称为虚函数。任何构造函数之外的非静态函数都可以是虚函数。

15.2

 主要区别在于派生类的成员函数及其友元是否有其访问权限,protected说明符修饰的基类成员可以被派生类成员函数及其友元访问,同时禁止派生类用户访问。而private说明符修饰的基类成员不能被派生类成员函数及其友元访问,也禁止派生类用户访问。

15.3

Quote.h

#ifndef _QUOTE_H
#define _QUOTE_H
#include <iostream>
#include <string>
class Quote
{public:Quote()=default;Quote(const std::string &book,double sales_price):price(sales_price),bookNo(book) {}std::string isbn() const {return bookNo;}virtual double net_price(std::size_t n) const {return n*price;}virtual std::string debug() const {return "bookNo="+bookNo+"\n"+"price="+std::to_string(price);}virtual ~Quote()=default;protected:double price=0.0;private:std::string bookNo;
};
double print_total(std::ostream &os,const Quote &item,std::size_t n);
class Bulk_quote:public Quote
{public:Bulk_quote()=default;Bulk_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),min_qty(qty),discount(disc) {}virtual double net_price(std::size_t n) const override{if(n>=min_qty)return n*(1-discount)*price;elsereturn n*price;}virtual std::string debug() const{return Quote::debug()+"\n"+"min_qty="+std::to_string(min_qty)+"\n"+"discount="+std::to_string(discount);}private:std::size_t min_qty=0;double discount=0.0;
};class Limit_quote:public Quote
{public:Limit_quote()=default;Limit_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),max_qty(qty),discount(disc) {}virtual double net_price(std::size_t n) const override{if(n<=max_qty)return n*(1-discount)*price;elsereturn max_qty*(1-discount)*price+(n-max_qty)*price;}virtual std::string debug() const{return Quote::debug()+"\n"+"max_qty="+std::to_string(max_qty)+"\n"+"discount="+std::to_string(discount);}private:std::size_t max_qty=0;double discount=0.0;
};
#endif

Quote.cpp

#include "Quote.h"
double print_total(std::ostream &os,const Quote &item,std::size_t n)
{double ret=item.net_price(n);os<<"ISBN: "<<item.isbn()<<" # sold: "<<n<<" total due: "<<ret<<std::endl;return ret;
}

15.4

  1. 错误,一个类不能派生它本身。
  2. 正确。
  3. 错误,派生类的声明中不可以包含它的派生列表。

15.5

见15.3

15.6

#include <iostream>
#include "Quote.h"
using namespace std;
int main(void)
{Quote item1("1-102-333",20);Bulk_quote item2("1-202-222",30,2,0.2);print_total(cout,item1,3);print_total(cout,item2,3);return 0;
}

15.7

class Limit_quote:public Quote
{public:Limit_quote()=default;Limit_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),max_qty(qty),discount(disc) {}virtual double net_price(std::size_t n) const override{if(n<=max_qty)return n*(1-discount)*price;elsereturn max_qty*(1-discount)*price+(n-max_qty)*price;}private:std::size_t max_qty=0;double discount=0.0;
};

15.8

静态类型是变量声明时的类型或表达式生成的类型,动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才可知。

15.9

 当基类的指针或引用指向派生类对象时,就会产生静态类型与动态类型不同的情况。

class base{......};
class derived:public base{......};
derived objd;
base *bp=&objd;//这三种情况静态类型与动态类型不同
base &bref=objd;//这三种情况静态类型与动态类型不同
base *bp=derived *dp=&objd;//这三种情况静态类型与动态类型不同

15.10

ifstream类型派生自istream类型,因此我们可以像使用istream对象一样使用ifstream对象。在read函数中,它接受一个istream类型的引用,所以作为它派生类,ifstream也可以绑定到istream的引用上。

15.11

见15.3

15.12

 有必要,override关键字指明该函数用于覆盖掉从基类继承而来的虚函数,这种用法可以避免我们在派生类中不经意间定义了一个与继承而来的虚函数同名但形参列表不同,而导致重新声明了一个与原虚函数相互独立的的函数的情况。而final关键字指明该函数不允许后续的派生类进行覆盖。这两个关键字功能并不重复,所以可以同时声明。

15.13

 两个print函数的目的都是打印各自的数据成员,其中派生类的print函数,函数体中会对自身版本的print函数进行调用,从而导致无限递归。派生类中的print函数应该改为void print(ostream &os) {base::print(os);os<<" "<<i;}

15.14

  1. 基类版本
  2. 派生类版本
  3. 基类版本
  4. 基类版本
  5. 基类版本
  6. 派生类版本

15.15

Quote.h

#ifndef _QUOTE_H
#define _QUOTE_H
#include <iostream>
#include <string>
class Quote
{public:Quote()=default;Quote(const std::string &book,double sales_price):price(sales_price),bookNo(book) {}std::string isbn() const {return bookNo;}virtual double net_price(std::size_t n) const {return n*price;}virtual std::string debug() const {return "bookNo="+bookNo+"\n"+"price="+std::to_string(price);}virtual ~Quote()=default;protected:double price=0.0;private:std::string bookNo;
};
class Disc_quote:public Quote
{public:Disc_quote()=default;Disc_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),quantity(qty),discount(disc) {}virtual double net_price(std::size_t n) const=0;virtual std::string debug() const override{return Quote::debug()+"\n"+"quantity="+std::to_string(quantity)+"\n"+"discount="+std::to_string(discount);}protected:std::size_t quantity=0;double discount=0.0;
};
double print_total(std::ostream &os,const Quote &item,std::size_t n);
class Bulk_quote:public Disc_quote
{public:Bulk_quote()=default;Bulk_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Disc_quote(book,sales_price,qty,disc) {}virtual double net_price(std::size_t n) const override{if(n>=quantity)return n*(1-discount)*price;elsereturn n*price;}
};
class Limit_quote:public Disc_quote
{public:Limit_quote()=default;Limit_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Disc_quote(book,sales_price,qty,disc) {}virtual double net_price(std::size_t n) const override{if(n<=quantity)return n*(1-discount)*price;elsereturn quantity*(1-discount)*price+(n-quantity)*price;}
};
#endif

Quote.cpp

#include "Quote.h"
double print_total(std::ostream &os,const Quote &item,std::size_t n)
{double ret=item.net_price(n);os<<"ISBN: "<<item.isbn()<<" # sold: "<<n<<" total due: "<<ret<<std::endl;return ret;
}

15.16

见15.15

15.17

test.cpp:5:20: error: cannot declare variable ‘item’ to be of abstract type ‘Disc_quote’

15.18

Base *p=&d1合法
p=&d2不合法,在用户代码层面,私有继承的派生类的基类部分是不可访问的
p=&d3不合法,在用户代码层面,保护继承的派生类的基类部分是不可访问的
p=&dd1合法
p=&dd2不合法,基类部分不可访问
p=&dd3不合法,基类部分不可访问

15.19

struct Derived_from_Private:public Priv_Derv这个类中的memfcn不合法。
 不论以何种方式继承,派生类的成员函数和友元都能使用派生类向基类的转换。派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的。
 如果派生类以公有或者受保护的方式继承,则派生类的派生类的成员和友元可以使用派生类向其基类的类型转换。如果以私有方式继承,则不能使用。

15.20

15.21

图形
平面图形
立体图形
方格
圆锥

其中图形、平面图形及立体图形类都是抽象基类.
以后再写

15.22

见15.21

15.23

class D1:public Base
{public:int fcn();virtual void f2();
};

bp2->fcn();虚调用,将在运行时调用D1::fcn.
p2->fcn(42);错误,D1中没有一个接受int的fcn.

15.24

 继承体系中的基类需要虚析构函数。虚析构函数可以在delete基类指针指向的派生类对象时,调用正确版本的析构函数。

15.25

 编译器只有在发现类不包含任何构造函数的情况下才会替我们生成一个合成的默认构造函数,因为Disc_quote定义了其它的构造函数,所以不会自动生成一个合成的默认构造函数,如此一来它的派生类Bulk_quote也不能生成合成的默认构造函数。

15.26

Quote.h

#ifndef _QUOTE_H
#define _QUOTE_H
#include <iostream>
#include <string>
class Quote
{public:Quote()=default;Quote(const Quote &rhs):price(rhs.price),bookNo(rhs.bookNo) {std::cout<<"Quote copy constructor"<<std::endl;}Quote(Quote &&rhs) noexcept :price(rhs.price),bookNo(std::move(rhs.bookNo)) {std::cout<<"Quote move constructor"<<std::endl;}Quote & operator=(const Quote &rhs){std::cout<<"Quote copy assignment operator"<<std::endl;price=rhs.price;bookNo=rhs.bookNo;return *this;}Quote & operator=(Quote &&rhs) noexcept{std::cout<<"Quote move assignment operator"<<std::endl;if(this!=&rhs){price=rhs.price;bookNo=std::move(rhs.bookNo);}return *this;}Quote(const std::string &book,double sales_price):price(sales_price),bookNo(book) {}std::string isbn() const {return bookNo;}virtual double net_price(std::size_t n) const {return n*price;}virtual std::string debug() const {return "bookNo="+bookNo+"\n"+"price="+std::to_string(price);}virtual ~Quote()=default;protected:double price=0.0;private:std::string bookNo;
};
double print_total(std::ostream &os,const Quote &item,std::size_t n);
class Bulk_quote:public Quote
{public:Bulk_quote()=default;Bulk_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),min_qty(qty),discount(disc) {}Bulk_quote(const Bulk_quote &rhs):Quote(rhs),min_qty(rhs.min_qty),discount(rhs.discount) {std::cout<<"Bulk_quote copy constructor"<<std::endl;}Bulk_quote(Bulk_quote &&rhs) noexcept : Quote(std::move(rhs)),min_qty(rhs.min_qty),discount(rhs.discount) {std::cout<<"Bulk_quote move constructor"<<std::endl;}Bulk_quote & operator=(const Bulk_quote &rhs){std::cout<<"Bulk_quote copy assignment operator"<<std::endl;Quote::operator=(rhs);min_qty=rhs.min_qty;discount=rhs.discount;return *this;}Bulk_quote & operator=(Bulk_quote &&rhs) noexcept{std::cout<<"Bulk_quote move assignment operator"<<std::endl;if(this!=&rhs){Quote::operator=(std::move(rhs));min_qty=rhs.min_qty;discount=rhs.discount;}return *this;}virtual double net_price(std::size_t n) const override{if(n>=min_qty)return n*(1-discount)*price;elsereturn n*price;}virtual std::string debug() const{return Quote::debug()+"\n"+"min_qty="+std::to_string(min_qty)+"\n"+"discount="+std::to_string(discount);}private:std::size_t min_qty=0;double discount=0.0;
};
#endif

Quote.cpp

#include "Quote.h"
double print_total(std::ostream &os,const Quote &item,std::size_t n)
{double ret=item.net_price(n);os<<"ISBN: "<<item.isbn()<<" # sold: "<<n<<" total due: "<<ret<<std::endl;return ret;
}

test.cpp

#include <iostream>
#include "Quote.h"
int main(void)
{Bulk_quote bulk("10-11-222",30,5,0.2);Quote qu=bulk;qu=bulk;Bulk_quote qu1=bulk;qu1=bulk;qu1=std::move(bulk);return 0;
}

15.26

Quote.h

#ifndef _QUOTE_H
#define _QUOTE_H
#include <iostream>
#include <string>
class Quote
{public:Quote()=default;Quote(const std::string &book,double sales_price):price(sales_price),bookNo(book) {}std::string isbn() const {return bookNo;}virtual double net_price(std::size_t n) const {return n*price;}virtual std::string debug() const {return "bookNo="+bookNo+"\n"+"price="+std::to_string(price);}virtual ~Quote()=default;protected:double price=0.0;private:std::string bookNo;
};
class Disc_quote:public Quote
{public:Disc_quote()=default;Disc_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),quantity(qty),discount(disc) {}virtual double net_price(std::size_t n) const=0;virtual std::string debug() const override{return Quote::debug()+"\n"+"quantity="+std::to_string(quantity)+"\n"+"discount="+std::to_string(discount);}protected:std::size_t quantity=0;double discount=0.0;
};
double print_total(std::ostream &os,const Quote &item,std::size_t n);
class Bulk_quote:public Disc_quote
{public:Bulk_quote()=default;
/*见此处*/	using Disc_quote::Disc::quote;virtual double net_price(std::size_t n) const override{if(n>=quantity)return n*(1-discount)*price;elsereturn n*price;}
};
class Limit_quote:public Disc_quote
{public:Limit_quote()=default;
/*见此处*/	using Disc_quote::Disc::quote;virtual double net_price(std::size_t n) const override{if(n<=quantity)return n*(1-discount)*price;elsereturn quantity*(1-discount)*price+(n-quantity)*price;}
};
#endif

15.28

test.cpp

#include <iostream>
#include <vector>
#include <memory>
#include "Quote.h"
using namespace std;
int main(void)
{/*15.28*/vector<Quote> Qvec;Qvec.push_back(Quote("10-100-111",20));Qvec.push_back(Bulk_quote("11-100-222",30,5,0.2));cout<<Qvec[0].net_price(10)+Qvec[1].net_price(10)<<endl;/*15.29*/vector<shared_ptr<Quote>> Qpvec;Qpvec.push_back(make_shared<Quote>("10-100-111",20));Qpvec.push_back(make_shared<Bulk_quote>("11-100-222",30,5,0.2));cout<<Qpvec[0]->net_price(10)+Qpvec[1]->net_price(10)<<endl;return 0;
}

15.29

见15.28
 不一致,原因在于第一次的vector中所有的元素都是Quote类,即使传入的是Bulk_quote,它也是被忽略掉派生类部分,然后保存到一个Quote类中。而第二次vector由于保存的是基类的只能指针,所以指向的对象既有可能是基类,也有可能是派生类,如此一来在调用net_price时就可以调用到派生类的函数版本。

15.30

Quote.h

#ifndef _QUOTE_H
#define _QUOTE_H
#include <set>
#include <iostream>
#include <string>
#include <memory>
class Quote
{public:Quote()=default;Quote(const std::string &book,double sales_price):price(sales_price),bookNo(book) {}std::string isbn() const {return bookNo;}virtual double net_price(std::size_t n) const {return n*price;}virtual std::string debug() const {return "bookNo="+bookNo+"\n"+"price="+std::to_string(price);}virtual Quote * clone() const & {return new Quote(*this);}virtual Quote * clone() && {return new Quote(std::move(*this));}virtual ~Quote()=default;protected:double price=0.0;private:std::string bookNo;
};
class Disc_quote:public Quote
{public:Disc_quote()=default;Disc_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Quote(book,sales_price),quantity(qty),discount(disc) {}virtual double net_price(std::size_t n) const=0;virtual std::string debug() const override{return Quote::debug()+"\n"+"quantity="+std::to_string(quantity)+"\n"+"discount="+std::to_string(discount);}protected:std::size_t quantity=0;double discount=0.0;
};
double print_total(std::ostream &os,const Quote &item,std::size_t n);
class Bulk_quote:public Disc_quote
{public:Bulk_quote()=default;Bulk_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Disc_quote(book,sales_price,qty,disc) {}virtual double net_price(std::size_t n) const override{if(n>=quantity)return n*(1-discount)*price;elsereturn n*price;}Bulk_quote * clone() const & {return new Bulk_quote(*this);}Bulk_quote * clone() && {return new Bulk_quote(std::move(*this));}
};
class Limit_quote:public Disc_quote
{public:Limit_quote()=default;Limit_quote(const std::string &book,double sales_price,std::size_t qty,double disc):Disc_quote(book,sales_price,qty,disc) {}virtual double net_price(std::size_t n) const override{if(n<=quantity)return n*(1-discount)*price;elsereturn quantity*(1-discount)*price+(n-quantity)*price;}
};
class basket
{public: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{double sum=0.0;for(std::multiset<std::shared_ptr<Quote>,decltype(compare) *>::const_iterator iter=items.cbegin();iter!=items.cend();iter=items.upper_bound(*iter))sum+=print_total(os,**iter,items.count(*iter));os<<"Total Sale: "<<sum<<std::endl;return sum;}private:static bool compare(const std::shared_ptr<Quote> &,const std::shared_ptr<Quote> &);std::multiset<std::shared_ptr<Quote>,decltype(compare) *> items{compare};
};
#endif

Quote.cpp

#include "Quote.h"
double print_total(std::ostream &os,const Quote &item,std::size_t n)
{double ret=item.net_price(n);os<<"ISBN: "<<item.isbn()<<" # sold: "<<n<<" total due: "<<ret<<std::endl;return ret;
}
bool basket::compare(const std::shared_ptr<Quote> &lhs,const std::shared_ptr<Quote> &rhs)
{return lhs->isbn()<rhs->isbn();
}

test.cpp

#include <iostream>
#include <vector>
#include <memory>
#include "Quote.h"
using namespace std;
int main(void)
{basket bsk;bsk.add_item(Quote("10-100-111",20));bsk.add_item(Bulk_quote("11-100-222",30,5,0.2));bsk.add_item(Bulk_quote("11-100-222",30,5,0.2));bsk.total_receipt(cout);return 0;
}

15.31

Query
NotQuery
OrQuery
WordQuery1
WordQuery2

同上
3.

Query1
WordQuery2
OrQuery3
WordQuery4
AndQuery5
WordQuery6
WordQuery7

15.32

 因为Query类未定义自己的控制成员函数,并且其只有一个shared_ptr类型的数据成员,所以Query类型的对象被拷贝、移动、赋值或销毁时,会调用shared_ptr类型相应的控制成员。

15.33

 因为Query_base类是一个抽象基类,我们不能直接创建一个抽象基类的对象,实际上在它的派生类对象被创建时,它才会作为其基类部分被创建。同时它没有定义控制成员函数,又不含数据成员,所以它在被拷贝、移动、赋值或销毁时会执行默认语义,什么都不做。

15.34

WordQuery(const std::string &) → \rightarrow fiery
Query(const std::string &) → \rightarrow fiery
WordQuery(const std::string &) → \rightarrow bird
Query(const std::string &) → \rightarrow bird
BinaryQuery(const Query &,const Query &,std::string) → \rightarrow (fiery,bird,&)
AndQuery(const Query &,const Query &) → \rightarrow (fiery,bird)
Query(std::shared_ptr<Query_base>)
WordQuery(const std::string &) → \rightarrow wind
Query(const std::string &) → \rightarrow wind
BinaryQuery(const Query &,const Query &,std::string) → \rightarrow ((fiery & bird),wind,|)
OrQuery(const Query &,const Query &) → \rightarrow ((fiery & bird),wind)
Query(std::shared_ptr<Query_base>)
2.
Query::rep
BinaryQuery::rep
Query::rep
WordQuery::rep
Query::rep
BinaryQuery::rep
Query::rep
WordQuery::rep
Query::rep
WordQuery::rep
3.
Query::eval
OrQuery::eval
Query::eval
WordQuery::eval
Query::eval
AndQuery::eval
Query::eval
WordQuery::eval
Query::eval
WordQuery::eval

15.35

class Query_base
{friend class Query;protected:using line_no=TextQuery::line_no;virtual ~Query_base()=default;private:virtual QueryResult eval(const TextQuery &) const=0;virtual std::string rep() 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 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;
};

15.36

参考15.39自行添加打印语句

15.37

 仅把派生类中的Query类型数据成员改成**shared_ptr<Query_base>**类型成员的话,影响并不大,因为Query类本来就有接受智能指针的构造函数,必要的地方手动类型转换即可。

15.38

  • 不合法,不能直接创建抽象基类的对象。
  • 不合法,AndQuery没有接受Query参数的构造函数。
  • 不合法,OrQuery没有接受Query参数的构造函数。

15.39

Query.h

#ifndef _QUERY_H
#define _QUERY_H
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <fstream>
class QueryResult;
class TextQuery
{public:using line_no=std::vector<std::string>::size_type;TextQuery(std::ifstream &);QueryResult query(const std::string &) const;private:std::shared_ptr<std::vector<std::string>> file;std::map<std::string,std::shared_ptr<std::set<line_no>>> wm;
};
class QueryResult
{friend std::ostream &print(std::ostream &,const QueryResult &);public:QueryResult(std::string s,std::shared_ptr<std::set<std::vector<std::string>::size_type>> l,std::shared_ptr<std::vector<std::string>> f):sought(s),lines(l),file(f){}std::set<std::vector<std::string>::size_type>::iterator begin() const {return lines->begin();}std::set<std::vector<std::string>::size_type>::iterator end() const {return lines->end();}std::shared_ptr<std::vector<std::string>> get_file(){return file;}private:std::string sought;std::shared_ptr<std::set<std::vector<std::string>::size_type>> lines;std::shared_ptr<std::vector<std::string>> file;
};
std::ostream &print(std::ostream &,const QueryResult &);
inline std::string make_plural(std::size_t count,const std::string &word,const std::string &ending)
{return (count>1)?word+ending:word;
}
class Query_base
{friend class Query;protected:using line_no=TextQuery::line_no;virtual ~Query_base()=default;private:virtual QueryResult eval(const TextQuery &) const=0;virtual std::string rep() 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 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;
};
class WordQuery:public Query_base
{friend class Query;private:WordQuery(const std::string &s):query_word(s) {}virtual QueryResult eval(const TextQuery &t) const {return t.query(query_word);}virtual std::string rep() const {return query_word;}std::string query_word;
};inline Query::Query(const std::string &s):q(new WordQuery(s)) {}class NotQuery:public Query_base
{friend Query operator~(const Query &);private:NotQuery(const Query &q):query(q) {}virtual QueryResult eval(const TextQuery &) const;virtual std::string rep() const {return "~("+query.rep()+")";}Query query;
};
inline Query operator~(const Query &q) {return std::shared_ptr<Query_base>(new NotQuery(q));}
class BinaryQuery:public Query_base
{protected:BinaryQuery(const Query &left,const Query &right,const std::string &s):lhs(left),rhs(right),opSym(s) {}virtual std::string rep() const {return "("+lhs.rep()+" "+opSym+" "+rhs.rep()+")";}Query lhs,rhs;std::string opSym;
};
class AndQuery:public BinaryQuery
{friend Query operator&(const Query&,const Query&);private:AndQuery(const Query &left,const Query &right):BinaryQuery(left,right,"&") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator&(const Query &left,const Query &right) {return std::shared_ptr<Query_base>(new AndQuery(left,right));}
class OrQuery:public BinaryQuery
{friend Query operator|(const Query &,const Query &);private:OrQuery(const Query &left,const Query &right):BinaryQuery(left,right,"|") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator|(const Query &left,const Query &right) {return std::shared_ptr<Query_base>(new OrQuery(left,right));}
inline std::ostream & operator<<(std::ostream &os,const Query &q) {return os<<q.rep();}
#endif

Query.cpp

#include <sstream>
#include <algorithm>
#include <cctype>
#include "Query.h"
TextQuery::TextQuery(std::ifstream &infile):file(new std::vector<std::string>)
{std::string text;while(getline(infile,text)){file->push_back(text);std::size_t line_number=file->size()-1;std::istringstream line(text);std::string word;while(line>>word){std::string key_word;for(auto c:word){if(!ispunct(c))key_word+=c;}std::shared_ptr<std::set<line_no>> &lines=wm[key_word];if(!lines)lines.reset(new std::set<line_no>);lines->insert(line_number);}}
}
QueryResult TextQuery::query(const std::string &sought) const
{static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);std::map<std::string,std::shared_ptr<std::set<line_no>>>::const_iterator map_it=wm.find(sought);if(map_it==wm.end())return QueryResult(sought,nodata,file);elsereturn QueryResult(sought,map_it->second,file);
}std::ostream &print(std::ostream &os,const QueryResult &qr)
{os<<"Executing Query for: "<<qr.sought<<std::endl;os<<qr.sought<<" occurs "<<qr.lines->size()<<" "<<make_plural(qr.lines->size(),"time","s")<<std::endl;for(auto num:*(qr.lines))os<<"\t(line "<<num+1<<") "<<*(qr.file->begin()+num)<<std::endl;return os;
}
QueryResult NotQuery::eval(const TextQuery &text) const
{auto result=query.eval(text);auto beg=result.begin(),end=result.end();auto ret_lines=std::make_shared<std::set<line_no>>();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());
}
QueryResult OrQuery::eval(const TextQuery &text) const
{auto left=lhs.eval(text),right=rhs.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());
}
QueryResult AndQuery::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());
}

test.cpp

#include <fstream>
#include "Query.h"
using namespace std;
int main(int argc,char *argv[])
{ifstream infile(argv[1]);TextQuery text(infile);Query q=Query("fiery")&Query("bird")|Query("wind");print(cout,q.eval(text));return 0;
}

15.40

set的构造函数和insert成员函数都可以正确处理空范围的情况,这种情况下得到的QueryResultlines成员指向的set也将是空的。

15.41

Query.h

#ifndef _QUERY_H
#define _QUERY_H
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <fstream>
class QueryResult;
class TextQuery
{public:using line_no=std::vector<std::string>::size_type;TextQuery(std::ifstream &);QueryResult query(const std::string &) const;private:std::shared_ptr<std::vector<std::string>> file;std::map<std::string,std::shared_ptr<std::set<line_no>>> wm;
};
class QueryResult
{friend std::ostream &print(std::ostream &,const QueryResult &);public:QueryResult(std::string s,std::shared_ptr<std::set<std::vector<std::string>::size_type>> l,std::shared_ptr<std::vector<std::string>> f):sought(s),lines(l),file(f){}std::set<std::vector<std::string>::size_type>::iterator begin() const {return lines->begin();}std::set<std::vector<std::string>::size_type>::iterator end() const {return lines->end();}std::shared_ptr<std::vector<std::string>> get_file(){return file;}private:std::string sought;std::shared_ptr<std::set<std::vector<std::string>::size_type>> lines;std::shared_ptr<std::vector<std::string>> file;
};
std::ostream &print(std::ostream &,const QueryResult &);
inline std::string make_plural(std::size_t count,const std::string &word,const std::string &ending)
{return (count>1)?word+ending:word;
}
class Query_base
{friend class Query;protected:using line_no=TextQuery::line_no;virtual ~Query_base()=default;private:virtual QueryResult eval(const TextQuery &) const=0;virtual std::string rep() 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 std::string &);Query(const Query &rhs):q(rhs.q),reference_count(rhs.reference_count) {++*reference_count;}Query & operator=(const Query &);~Query();QueryResult eval(const TextQuery &t) const {return q->eval(t);}std::string rep() const {return q->rep();}private:Query(Query_base *query):q(query),reference_count(new std::size_t(1)) {}Query_base *q;std::size_t *reference_count;
};
class WordQuery:public Query_base
{friend class Query;private:WordQuery(const std::string &s):query_word(s) {}virtual QueryResult eval(const TextQuery &t) const {return t.query(query_word);}virtual std::string rep() const {return query_word;}std::string query_word;
};inline Query::Query(const std::string &s):q(new WordQuery(s)),reference_count(new std::size_t(1)) {}class NotQuery:public Query_base
{friend Query operator~(const Query &);private:NotQuery(const Query &q):query(q) {}virtual QueryResult eval(const TextQuery &) const;virtual std::string rep() const {return "~("+query.rep()+")";}Query query;
};
inline Query operator~(const Query &q) {return new NotQuery(q);}
class BinaryQuery:public Query_base
{protected:BinaryQuery(const Query &left,const Query &right,const std::string &s):lhs(left),rhs(right),opSym(s) {}virtual std::string rep() const {return "("+lhs.rep()+" "+opSym+" "+rhs.rep()+")";}Query lhs,rhs;std::string opSym;
};
class AndQuery:public BinaryQuery
{friend Query operator&(const Query&,const Query&);private:AndQuery(const Query &left,const Query &right):BinaryQuery(left,right,"&") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator&(const Query &left,const Query &right) {return new AndQuery(left,right);}
class OrQuery:public BinaryQuery
{friend Query operator|(const Query &,const Query &);private:OrQuery(const Query &left,const Query &right):BinaryQuery(left,right,"|") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator|(const Query &left,const Query &right) {return new OrQuery(left,right);}
inline std::ostream & operator<<(std::ostream &os,const Query &q) {return os<<q.rep();}
#endif

Query.cpp

#include <sstream>
#include <algorithm>
#include <cctype>
#include "Query.h"
TextQuery::TextQuery(std::ifstream &infile):file(new std::vector<std::string>)
{std::string text;while(getline(infile,text)){file->push_back(text);std::size_t line_number=file->size()-1;std::istringstream line(text);std::string word;while(line>>word){std::string key_word;for(auto c:word){if(!ispunct(c))key_word+=c;}std::shared_ptr<std::set<line_no>> &lines=wm[key_word];if(!lines)lines.reset(new std::set<line_no>);lines->insert(line_number);}}
}
QueryResult TextQuery::query(const std::string &sought) const
{static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);std::map<std::string,std::shared_ptr<std::set<line_no>>>::const_iterator map_it=wm.find(sought);if(map_it==wm.end())return QueryResult(sought,nodata,file);elsereturn QueryResult(sought,map_it->second,file);
}std::ostream &print(std::ostream &os,const QueryResult &qr)
{os<<"Executing Query for: "<<qr.sought<<std::endl;os<<qr.sought<<" occurs "<<qr.lines->size()<<" "<<make_plural(qr.lines->size(),"time","s")<<std::endl;for(auto num:*(qr.lines))os<<"\t(line "<<num+1<<") "<<*(qr.file->begin()+num)<<std::endl;return os;
}
Query & Query::operator=(const Query &rhs)
{++*rhs.reference_count;if(--*reference_count==0){delete q;delete reference_count;}q=rhs.q;reference_count=rhs.reference_count;return *this;
}
Query::~Query()
{if(--*reference_count==0){delete q;delete reference_count;}
}
QueryResult NotQuery::eval(const TextQuery &text) const
{auto result=query.eval(text);auto beg=result.begin(),end=result.end();auto ret_lines=std::make_shared<std::set<line_no>>();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());
}
QueryResult OrQuery::eval(const TextQuery &text) const
{auto left=lhs.eval(text),right=rhs.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());
}
QueryResult AndQuery::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());
}

15.42

按句子查询并打印单词,而不再是按行打印。
Query.h

#ifndef _QUERY_H
#define _QUERY_H
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <fstream>
class QueryResult;
class TextQuery
{public:using line_no=std::vector<std::string>::size_type;TextQuery(std::ifstream &);QueryResult query(const std::string &) const;private:std::shared_ptr<std::vector<std::string>> file;std::map<std::string,std::shared_ptr<std::set<line_no>>> wm;
};
class QueryResult
{friend std::ostream &print(std::ostream &,const QueryResult &);public:QueryResult(std::string s,std::shared_ptr<std::set<std::vector<std::string>::size_type>> l,std::shared_ptr<std::vector<std::string>> f):sought(s),lines(l),file(f){}std::set<std::vector<std::string>::size_type>::iterator begin() const {return lines->begin();}std::set<std::vector<std::string>::size_type>::iterator end() const {return lines->end();}std::shared_ptr<std::vector<std::string>> get_file(){return file;}private:std::string sought;std::shared_ptr<std::set<std::vector<std::string>::size_type>> lines;std::shared_ptr<std::vector<std::string>> file;
};
std::ostream &print(std::ostream &,const QueryResult &);
inline std::string make_plural(std::size_t count,const std::string &word,const std::string &ending)
{return (count>1)?word+ending:word;
}
class Query_base
{friend class Query;protected:using line_no=TextQuery::line_no;virtual ~Query_base()=default;private:virtual QueryResult eval(const TextQuery &) const=0;virtual std::string rep() 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 std::string &);Query(const Query &rhs):q(rhs.q),reference_count(rhs.reference_count) {++*reference_count;}Query & operator=(const Query &);~Query();QueryResult eval(const TextQuery &t) const {return q->eval(t);}std::string rep() const {return q->rep();}private:Query(Query_base *query):q(query),reference_count(new std::size_t(1)) {}Query_base *q;std::size_t *reference_count;
};
class WordQuery:public Query_base
{friend class Query;private:WordQuery(const std::string &s):query_word(s) {}virtual QueryResult eval(const TextQuery &t) const {return t.query(query_word);}virtual std::string rep() const {return query_word;}std::string query_word;
};inline Query::Query(const std::string &s):q(new WordQuery(s)),reference_count(new std::size_t(1)) {}class NotQuery:public Query_base
{friend Query operator~(const Query &);private:NotQuery(const Query &q):query(q) {}virtual QueryResult eval(const TextQuery &) const;virtual std::string rep() const {return "~("+query.rep()+")";}Query query;
};
inline Query operator~(const Query &q) {return new NotQuery(q);}
class BinaryQuery:public Query_base
{protected:BinaryQuery(const Query &left,const Query &right,const std::string &s):lhs(left),rhs(right),opSym(s) {}virtual std::string rep() const {return "("+lhs.rep()+" "+opSym+" "+rhs.rep()+")";}Query lhs,rhs;std::string opSym;
};
class AndQuery:public BinaryQuery
{friend Query operator&(const Query&,const Query&);private:AndQuery(const Query &left,const Query &right):BinaryQuery(left,right,"&") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator&(const Query &left,const Query &right) {return new AndQuery(left,right);}
class OrQuery:public BinaryQuery
{friend Query operator|(const Query &,const Query &);private:OrQuery(const Query &left,const Query &right):BinaryQuery(left,right,"|") {}virtual QueryResult eval(const TextQuery &) const;
};
inline Query operator|(const Query &left,const Query &right) {return new OrQuery(left,right);}
inline std::ostream & operator<<(std::ostream &os,const Query &q) {return os<<q.rep();}
#endif

Query.cpp

#include <sstream>
#include <algorithm>
#include <cctype>
#include "Query.h"
TextQuery::TextQuery(std::ifstream &infile):file(new std::vector<std::string>)
{std::string text;while(getline(infile,text,'.')){for(decltype(text.size()) index=0;index!=text.size();++index){if(text[index]=='\n')text[index]=' ';}file->push_back(text);std::size_t line_number=file->size()-1;std::istringstream line(text);std::string word;while(line>>word){std::string key_word;for(auto c:word){if(!ispunct(c))key_word+=c;}std::shared_ptr<std::set<line_no>> &lines=wm[key_word];if(!lines)lines.reset(new std::set<line_no>);lines->insert(line_number);}}
}
QueryResult TextQuery::query(const std::string &sought) const
{static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);std::map<std::string,std::shared_ptr<std::set<line_no>>>::const_iterator map_it=wm.find(sought);if(map_it==wm.end())return QueryResult(sought,nodata,file);elsereturn QueryResult(sought,map_it->second,file);
}std::ostream &print(std::ostream &os,const QueryResult &qr)
{os<<"Executing Query for: "<<qr.sought<<std::endl;os<<qr.sought<<" occurs "<<qr.lines->size()<<" "<<make_plural(qr.lines->size(),"time","s")<<std::endl;for(auto num:*(qr.lines))os<<"\t(sentence "<<num+1<<") "<<*(qr.file->begin()+num)<<"."<<std::endl;return os;
}
Query & Query::operator=(const Query &rhs)
{++*rhs.reference_count;if(--*reference_count==0){delete q;delete reference_count;}q=rhs.q;reference_count=rhs.reference_count;return *this;
}
Query::~Query()
{if(--*reference_count==0){delete q;delete reference_count;}
}
QueryResult NotQuery::eval(const TextQuery &text) const
{auto result=query.eval(text);auto beg=result.begin(),end=result.end();auto ret_lines=std::make_shared<std::set<line_no>>();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());
}
QueryResult OrQuery::eval(const TextQuery &text) const
{auto left=lhs.eval(text),right=rhs.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());
}
QueryResult AndQuery::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());
}

这篇关于c++ primer中文版第五版作业第十五章的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/788597

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

c++中std::placeholders的使用方法

《c++中std::placeholders的使用方法》std::placeholders是C++标准库中的一个工具,用于在函数对象绑定时创建占位符,本文就来详细的介绍一下,具有一定的参考价值,感兴... 目录1. 基本概念2. 使用场景3. 示例示例 1:部分参数绑定示例 2:参数重排序4. 注意事项5.

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

使用C/C++调用libcurl调试消息的方式

《使用C/C++调用libcurl调试消息的方式》在使用C/C++调用libcurl进行HTTP请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试,libcurl提供了多种... 目录1. libcurl 调试工具简介2. 输出请求消息使用 CURLOPT_VERBOSE使用 C

C++实现获取本机MAC地址与IP地址

《C++实现获取本机MAC地址与IP地址》这篇文章主要为大家详细介绍了C++实现获取本机MAC地址与IP地址的两种方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实际工作中,项目上常常需要获取本机的IP地址和MAC地址,在此使用两种方案获取1.MFC中获取IP和MAC地址获取