15.1
派生类必须有的,而且需要定义自己版本的成员,该成员隐式的也是虚成员
15.2
protected说明成员是受保护的:只有该类对象成员和派生类可以访问,派生类的派生类无访问权
private说明成员是私有的:是有该类对象的成员才有访问权,派生类没有
15.3
#pragma once #include <iostream> #include <string> class Quote { //私有的 只允许本对象成员访问 std::string bookNo; protected: //保护的 允许直接派生对象成员访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) {} std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual ~Quote() = default; }; 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; }
a: 错误,类不能派生它本身
b: 正确
c: 错误,缺少定义
15.5
class Bulk_quote :public Quote { std::size_t min_qty = 0; double discount = 0.0; public: Bulk_quote() = default; Bulk_quote(std::string &book, double sales_price, std::size_t min, double count) :Quote(book, sales_price), min_qty(min), discount(count) {} double net_price(std::size_t n)const override //覆盖基类版本 { if (n >= min_qty) return (1 - discount)*price*n; return n*price; } };
#include "head.h" #include <iostream> int main()//15.6 { using namespace std; Quote b1("c++ primer5", 128); Bulk_quote b2("c++ primer4", 128.0, 10, 0.7); print_total(cout, b1, 10); print_total(cout, b2, 10); system("pause"); return 0; }
class Activity_quote :public Quote //15.7 { double discount= 0.0; std::size_t min_qty = 0; std::size_t max_qty = 0; public: Activity_quote() = default; Activity_quote(const std::string &book, double sales_price, std::size_t min, std::size_t max, double count) :Quote(book, sales_price), min_qty(min), max_qty(max), discount(count) {} double net_price(std::size_t n)const override { if (n >= min_qty) { if (n > max_qty) return (n - max_qty)*price + max_qty*discount*price; return discount*n*price; } } };
静态类型:在编译阶段已知,是对象声明的类型或表达式的类型。
动态类型:在运行阶段知晓,是对象保存在内存中的类型。
比如说print_total()函数的形参就有一个Quote&,我们知道它的类型是Quote&,但是不知道它绑定到动态内存中的对象是Quote还是Bulk_quote。
15.9
就像是引用或指针指向的类型可能与引用或指针的类型不一样差不多:
例如书上的函数print_total(...,Quote &q,...);&q是引用类型,但是我们不知道运行时传递给&q的是Quote还是Bulk_quote,所以Quote&是静态类型,动态类型是目标的类型
15.10
可以看出来,istream类是ifstream的基类,而istream类的成员与ifstream类的操作无异,可以可以猜测istream类的成员基本上是虚函数,而ifstream类有自己的override版本,所以操作基本共用。
当我们把ifstream绑定到istream引用时,我们只能使用ifstream中的istream基类的成员,但是因为动态类型绑定的,所以使用的是虚版本。
15.11
#pragma once #include <iostream> #include <string> class Quote { //私有的 只允许对象成员访问 std::string bookNo; protected: //保护的 允许直接派生类访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) {} std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual void debug()const //15.11 { std::cout << bookNo << " " << price; } virtual ~Quote() = default; }; class Bulk_quote :public Quote //15.5 { double discount = 0.0; std::size_t min_qty = 0; public: Bulk_quote() = default; Bulk_quote(const std::string &book, double sales_price, std::size_t min, double count) :Quote(book, sales_price), min_qty(min), discount(count) {} double net_price(std::size_t n)const override //覆盖基类版本 { if (n >= min_qty) return discount*price*n; return n*price; } void debug()const override //15.11 { Quote::debug(); std::cout << " " << min_qty << " " << discount; } }; class Activity_quote :public Quote //15.7 { double discount= 0.0; std::size_t min_qty = 0; std::size_t max_qty = 0; public: Activity_quote() = default; Activity_quote(const std::string &book, double sales_price, std::size_t min, std::size_t max, double count) :Quote(book, sales_price), min_qty(min), max_qty(max), discount(count) {} double net_price(std::size_t n)const override { if (n >= min_qty) { if (n > max_qty) return (n - max_qty)*price + max_qty*discount*price; return discount*n*price; } return n*price; } void debug()const override //15.11 { Quote::debug(); std::cout << " " << min_qty << " " << max_qty << " " << discount; } }; 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.12
看情况,如果希望该派生类派生出的派生类不允许覆盖该成员,那就可以这么做,比如上面的Bulk_quote的dubug,如果Bulk_quote不希望它的派生类覆盖,那么可以声明为:void dubug() const final override;
15.13
第一个print打印基类的basename
第二个将造成死循环,因为会一直调用派生类的print而不是调用基类的,因为它忽略了作用域运算符。
改为base::print(os);
15.14
a:基类
b:派生类
c:基类
d:派生类
e:基类
f:派生类
15.15
#pragma once #include <iostream> #include <string> class Quote { //私有的 只允许对象成员访问 std::string bookNo; protected: //保护的 允许直接派生类访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) {} std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual void debug()const //15.11 { std::cout << bookNo << " " << price; } virtual ~Quote() = default; }; class Disc_qoute :public Quote { protected: //派生类需要访问,所以用保护 std::size_t quantity = 0; double discount = 0.0; public: Disc_qoute() = default; Disc_qoute(const std::string &book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) {} double net_price(std::size_t n)const = 0; //纯虚函数 }; class Bulk_quote :public Disc_qoute { public: Bulk_quote() = default; Bulk_quote(std::string &book, double price, std::size_t qty, double disc) :Disc_qoute(book, price, qty, disc) {} double net_price(std::size_t n)const override { if (n >= quantity) return discount*n*price; return n*price; } };
#pragma once #include <iostream> #include <string> class Quote { //私有的 只允许对象成员访问 std::string bookNo; protected: //保护的 允许直接派生类访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) {} std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual void debug()const //15.11 { std::cout << bookNo << " " << price; } virtual ~Quote() = default; }; class Disc_qoute :public Quote { protected: //派生类需要访问,所以用保护 std::size_t quantity = 0; double discount = 0.0; public: Disc_qoute() = default; Disc_qoute(const std::string &book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) {} double net_price(std::size_t n)const = 0; //纯虚函数 }; class Bulk_quote :public Disc_qoute { public: Bulk_quote() = default; Bulk_quote(const std::string &book, double price, std::size_t qty, double disc) :Disc_qoute(book, price, qty, disc) {} double net_price(std::size_t n)const override { if (n >= quantity) return discount*n*price; return n*price; } }; class Activity_quote :public Disc_qoute { std::size_t max = 0; public: Activity_quote() = default; Activity_quote(const std::string &book, double price, std::size_t min_qty, std::size_t max_qty, double disc) :Disc_qoute(book, price, min_qty, disc), max(max_qty) {} double net_price(std::size_t n)const override { if (n >= quantity) { if (n > max) return (n - max)*price + max*discount*price; return n*discount*price; } return n*price; } }; 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; }
错误:不允许使用抽象数据类型“Disc_quote”的的对象;
函数“Disc_quote::net_price”是纯虚拟函数
15.18
只有当派生类公有继承基类时,用户代码才能使用派生类向基类的转换:B &tb=D;
Base *p=&d1; 正确,Pub_Derv是公有继承Base
p=&d2; 错误,Priv_Derv是私有继承Base
p=&d3; 错误,Prot_Dery是保护继承Base
p=&dd1; 正确,Derived_from_Public是公有继承于Pub_Dery的
p=&dd2; 错误,Priv_Derv是私有继承于Base
p=&dd3; 错误,Prot_Dery是保护继承于Base
15.19
如果派生类D继承基类B的方式是公有或保护,则派生类D的派生出来的派生类E的成员和友元可以使用派生类D向基类B的类型转换;反之,如果派生类D继承基类B的方式是私有的,则不能用。
class Base { char priv; protected: int prot; public: void pub() {} void memfcn(Base &b) { b = *this; } //正确 }; struct Pub_Dery :public Base { void memfcn(Base &b) { b = *this; } //正确 int f() { return prot; } }; struct Prot_Dery :protected Base { void memfcn(Base &b) { b = *this; } //正确 }; struct Priv_Dery:private Base { void memfcn(Base &b) { b = *this; } //正确 int f1() { return prot; } }; struct dfpub :public Pub_Dery { void memfcn(Base &b) { b = *this; } //正确,公有继承派生类的派生类可以访问其公有与保护部分 int use_base() { return prot; } }; struct dfpro:public Prot_Dery { void memfcn(Base &b) { b = *this; } //正确,保护继承派生类的派生类可以访问其保护部分 }; struct dfpri :public Priv_Dery { void memfcn(Base &b) { b = *this; } //错误,Base类型不可访问,不允许对不可访问的基类“base”进行转换。原因是Priv_Dery是私有继承Base的,所以对于dfpri来说,其Priv_Dery部分的base部分是私有的 };
[]~( ̄▽ ̄)~*
15.21、15.22
#pragma once #include <string> #include <iostream> class NPC { std::string name; unsigned hp; unsigned level; protected: virtual void ChangeHP(unsigned n) { if (n <= hp) hp -= n; else hp = 0; std::cout << name << " 受到了 " << n << " 伤害\n"; }; unsigned atk; bool IsDeath()const { if (hp == 0) return true; return false; } public: NPC() = default; NPC(const std::string &_name, unsigned _hp, unsigned _level, unsigned _atk) :name(_name), hp(_hp), level(_level), atk(_atk) {} virtual void hurt(unsigned n) = 0; virtual void Attack(NPC &n) = 0; virtual void show()const { std::cout << name << "\nlevel:\t" << level << "\natk:\t" << atk << "\nhp:" << hp << "\n"; } }; class monster:public NPC { unsigned defense = 0; //5点防御降低一点攻击 public: monster() = default; monster(const std::string &_name, unsigned _hp, unsigned _level, unsigned _atk, unsigned _def) :NPC(_name,_hp,_level,_atk), defense(_def) {} void hurt(unsigned n) //受到伤害 { if (IsDeath()) { std::cout << "目标已死亡\n"; return; } ChangeHP(n - defense / 5); show(); } void Attack(NPC &n) //攻击 { n.hurt(atk); } void show()const { NPC::show(); std::cout << "defense:\t" << defense << "\n\n"; } }; class play :public NPC { unsigned defense = 0; //5点防御降低一点攻击 unsigned skill = 0; //每1级增加1点攻击力,提升0.5防御力 public: play() = default; play(const std::string &_name, unsigned _hp, unsigned _level, unsigned _atk, unsigned _def, unsigned _skill) :NPC(_name, _hp, _level, _atk), defense(_def), skill(_skill) {} void hurt(unsigned n) //受到伤害 { if (IsDeath()) { std::cout << "目标已死亡\n"; return; } ChangeHP(n - defense / 5 - skill / 2); show(); } void Attack(NPC &n) //攻击 { n.hurt(atk + skill * 1); } void show()const { NPC::show(); std::cout << "defense:\t" << defense << "\n" << "skill:\t" << skill << "\n\n"; } }; //......
15.23
int fcn()override;
bp2->fcn();将调用D1::fcn,覆盖Base的fcn
15.24
作为基类的类需要虚析构函数
基类的析构函数必须是虚的,以完成继承层次的类动态分配和销毁
15.25
因为定义了一个构造函数,所以编译器将不会提供默认构造函数,当定义一个默认值的对象时会出错
15.26
#pragma once #include <iostream> #include <string> class Quote { //私有的 只允许对象成员访问 std::string bookNo; protected: //保护的 允许直接派生类访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) { std::cout << "q c" << std::endl; } Quote(Quote &q) :bookNo(q.bookNo), price(q.price) { std::cout << "q copy"<<std::endl; } Quote(Quote &&q) :bookNo(std::move(q.bookNo)), price(q.price) { std::cout << "q move" << std::endl; } Quote &operator=(Quote &q) { bookNo = q.bookNo; price = q.price; std::cout << "q =" << std::endl; return *this; } Quote &operator=(Quote &&q) { bookNo = std::move(q.bookNo); price = q.price; std::cout << "q =" << std::endl; return *this; } std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual void debug()const //15.11 { std::cout << bookNo << " " << price; } virtual ~Quote(){ std::cout << "q del" <<bookNo<< std::endl; } }; class Disc_qoute :public Quote { protected: //派生类需要访问,所以用保护 std::size_t quantity = 0; double discount = 0.0; public: Disc_qoute() = default; Disc_qoute(const std::string &book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) { std::cout << "b c" << std::endl; } double net_price(std::size_t n)const = 0; //纯虚函数 }; class Bulk_quote :public Disc_qoute { public: Bulk_quote() = default; Bulk_quote(const std::string &book, double price, std::size_t qty, double disc) :Disc_qoute(book, price, qty, disc) {} Bulk_quote(Bulk_quote &b) :Disc_qoute(b) { std::cout << "b copy" << std::endl; } Bulk_quote(Bulk_quote &&b) :Disc_qoute(std::move(b)) { std::cout << "b move" << std::endl; } Bulk_quote &operator=(Bulk_quote &b) { Disc_qoute::operator=(b); std::cout << "b =" << std::endl; return *this; } Bulk_quote &operator=(Bulk_quote &&b) { Disc_qoute::operator=(std::move(b)); std::cout << "b =" << std::endl; return *this; } double net_price(std::size_t n)const override { if (n >= quantity) return discount*n*price; return n*price; } ~Bulk_quote() { std::cout << "b del" << std::endl; } }; class Activity_quote :public Disc_qoute { std::size_t max = 0; public: Activity_quote() = default; Activity_quote(const std::string &book, double price, std::size_t min_qty, std::size_t max_qty, double disc) :Disc_qoute(book, price, min_qty, disc), max(max_qty) {} double net_price(std::size_t n)const override { if (n >= quantity) { if (n > max) return (n - max)*price + max*discount*price; return n*discount*price; } return n*price; } }; 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; }
#include "标头.h" #include <iostream> int func() { using namespace std; Activity_quote abook("c++primer5", 129.0, 10, 100, 0.8); //q c b c Bulk_quote bbook("c++ primer plus 6", 119.0, 20, 0.85); //q c b c Bulk_quote bb(bbook); //q copy b copy Bulk_quote mb(std::move(bbook)); //q move b move bb = mb; //q = b = Activity_quote aab(abook); //q copy Activity_quote ma(std::move(abook)); //q move aab = ma; //q = return 0; //从ma开始到abook释放 从对象的派生类到基类 如ma:先释放自己的内容,然后调用基类的析构 // 所以输出: q del c++primer5 // abb: q del c++primer5 // mb: b del // q del c++ primer plus 6 // bb: b del // q del c++ primer plus 6 // bbook: b del // q del // abook: q del } int main() { func(); system("pause"); return 0; }
class Bulk_quote :public Disc_qoute { public: using Disc_qoute::Disc_qoute; Bulk_quote() = default; Bulk_quote(const std::string &book, double price, std::size_t qty, double disc) :Disc_qoute(book, price, qty, disc) {} Bulk_quote(Bulk_quote &b) :Disc_qoute(b) { std::cout << "b copy" << std::endl; } Bulk_quote(Bulk_quote &&b) :Disc_qoute(std::move(b)) { std::cout << "b move" << std::endl; } Bulk_quote &operator=(Bulk_quote &b) { Disc_qoute::operator=(b); std::cout << "b =" << std::endl; return *this; } Bulk_quote &operator=(Bulk_quote &&b) { Disc_qoute::operator=(std::move(b)); std::cout << "b =" << std::endl; return *this; } double net_price(std::size_t n)const override { if (n >= quantity) return discount*n*price; return n*price; } ~Bulk_quote() { std::cout << "b del" << std::endl; } };
#include "head.h" #include <iostream> #include <vector> #include <memory> //shared_ptr int main() { using namespace std; vector<Quote> qvec; for (int i = 1; i <= 5; ++i) qvec.push_back(Bulk_quote("s"+string(i,'s'),10*i,10,0.9)); double sum = 0; for (auto x : qvec) sum += x.net_price(10); cout << sum << endl; return 0; }
15.29
#include "标头.h" #include <iostream> #include <vector> #include <memory> //shared_ptr int main() { using namespace std; vector<shared_ptr<Quote>> qvec; for (int i = 1; i <= 5; ++i) qvec.push_back(make_shared<Bulk_quote>("s"+string(i,'s'),10*i,10,0.9)); double sum = 0; for (auto x : qvec) sum += x->net_price(10); cout << sum << endl; system("pause"); return 0; }不一致,前者的qvec是调用Quote对象的net_price,而且qvec添加元素时只是添加了基类Quote部分,其他的被切掉
而后者使用的是智能指针,当qvec添加元素时指向Buls_quote对象的智能指针,所以不会被切掉,然后调用net_quote时也是通过指针的对象调用,所以能正确的调用net_price的版本
15.30
#pragma once #include <iostream> #include <string> #include <set> #include <memory> class Quote { //私有的 只允许对象成员访问 std::string bookNo; protected: //保护的 允许直接派生类访问 double price = 0.0; public: //公有的 运行所有对象访问 Quote() = default; Quote(const std::string &book, double sales_price) :bookNo(book), price(sales_price) {} Quote(const Quote &q) :bookNo(q.bookNo), price(q.price) {} Quote(Quote &&q) :bookNo(std::move(q.bookNo)), price(q.price) {} Quote &operator=(Quote &q) { bookNo = q.bookNo; price = q.price; return *this; } Quote &operator=(Quote &&q) { bookNo = std::move(q.bookNo); price = q.price; return *this; } std::string isbn()const { return bookNo; } virtual double net_price(std::size_t n)const { return n*price; } virtual void debug()const //15.11 { std::cout << bookNo << " " << price; } virtual Quote *clone()const & //15.30 { return new Quote(*this); } virtual Quote *clone() && //15.30 { return new Quote(std::move(*this)); } virtual ~Quote() {} }; class Disc_qoute :public Quote { protected: //派生类需要访问,所以用保护 std::size_t quantity = 0; double discount = 0.0; public: Disc_qoute() = default; Disc_qoute(const std::string &book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) {} double net_price(std::size_t n)const = 0; //纯虚函数 }; class Bulk_quote :public Disc_qoute { public: Bulk_quote() = default; Bulk_quote(const std::string &book, double price, std::size_t qty, double disc) :Disc_qoute(book, price, qty, disc) {} Bulk_quote(const Bulk_quote &b) :Disc_qoute(b) {} Bulk_quote(Bulk_quote &&b) :Disc_qoute(std::move(b)) {} Bulk_quote &operator=(Bulk_quote &b) { Disc_qoute::operator=(b); return *this; } Bulk_quote &operator=(Bulk_quote &&b) { Disc_qoute::operator=(std::move(b)); return *this; } double net_price(std::size_t n)const override { if (n >= quantity) return discount*n*price; return n*price; } Bulk_quote *clone()const& //15.30 { return new Bulk_quote(*this); } Bulk_quote *clone() && //15.30 { return new Bulk_quote(std::move(*this)); } ~Bulk_quote() {} }; class Activity_quote :public Disc_qoute { std::size_t max = 0; public: Activity_quote() = default; Activity_quote(const std::string &book, double price, std::size_t min_qty, std::size_t max_qty, double disc) :Disc_qoute(book, price, min_qty, disc), max(max_qty) {} double net_price(std::size_t n)const override { if (n >= quantity) { if (n > max) return (n - max)*price + max*discount*price; return n*discount*price; } return n*price; } }; class Basket { static bool compare(const std::shared_ptr<Quote> rhs, const std::shared_ptr<Quote> lhs) { return rhs->isbn() < lhs->isbn(); } std::multiset<std::shared_ptr<Quote>, decltype(compare)*> items{ compare }; //使用compare来排序 public: void add_item(const std::shared_ptr<Quote> &sale) { items.insert(sale); } void add_item(const Quote &q) { items.insert(std::shared_ptr<Quote>(q.clone())); } void add_item(Quote &&q) { items.insert(std::shared_ptr<Quote>(std::move(q).clone())); } double total_receipt(std::ostream &os)const; }; 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; } double Basket::total_receipt(std::ostream &os)const { double sum = 0.0; //iter指向下一个与当前书名不同的元素 for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)) { sum += print_total(os, **iter, items.count(*iter)); //items.count返回当前书本在multiset里的数量 } os << "Total Sale: " << sum << std::endl; return sum; }
#include "head.h" int main() { using namespace std; Basket b1; string bookn; double price, discount; size_t quantity; char ch; while (1) { cout << "enter title(enter 'quit' to exit):"; getline(cin, bookn); if (bookn == "quit") break; cout << "enter price"; cin >> price; cout << "whether the discount?(y/n):"; cin >> ch; if (ch == 'n') { b1.add_item(Quote(bookn, price)); continue; } cout << "enter enter purchase quantity and discount get a discount:"; cin >> quantity >> discount; b1.add_item(Bulk_quote(bookn, price, quantity, discount)); while (cin.get() != '\n') continue; } b1.total_receipt(cout); system("pause"); return 0; }
a:OrQuery、AndQuery、NotQuery、WordQuery
b:同上
c:AndQuery、OrQuery、WordQuery
15.32
拷贝:调用合成的拷贝构造函数,将智能指针q的内容复制到新对象的对应成员,使智能指针q计数+1
移动:调用合成的移动构造函数,将智能指针q的内容移动到新对象的对应成员,使智能指针q指向NULL
赋值:调用合成的拷贝赋值运算符,将智能指针q的内容替换为参数对象的对应成员的内容,使q计数-1,并让参数计数+1
摧毁:调用合成的析构函数,清理自身,并调用q的析构函数,使计数-1
15.33
由于没有数据成员,所以合成的拷贝控制足以应付所有问题
15.34
Query qy = Query("fiery") & Query("bird") | Query("wind");
a:首先对等号右边求值:
Query("fiery")、 Query("bird")、Query("wind"):创建WordQuery
——Query(const string &);
————WordQuery(const string &);
——————Query_base();
——————string(string &);
首先创建三个Query对象,而Query会创建WordQuery对象并让基类智能指针q指向,而WordQuery公有派生于Query_base,并包含有一个string
Query("fiery") &Query("bird"):创建AndQuery
————AndQuery(const Query &,const Query &);
——————BinaryQuery(const Query &,const Query &);
————————Query_base();
————————Query(Query &);
————————string(string &);
运算符operator&(const Query &,const Query &)创建AndQuery对象,在返回std::shared_ptr<Query_base>(new AndQuery(lhs, rhs))创建的智能指针时会调用Query(shared_ptr<Query_base>)来创建返回值,而AndQuery公有派生于BinaryQuery,BinaryQuery公有派生于Query_base并包含两个Query对象与string对象,
(Query("fiery") & Query("bird")) |Query("wind") :创建OrQuery
————OrQuery(const Query,const Query &);
——————BinaryQuery(const Query &,const Query &);
————————Query_base();
————————Query(Query &);
————————string(string &);
与运算符operator&(const Query &,const Query &)类似
OrQuery公有派生于BinaryQuery,以下略
等号左边:使用Query(const Query &)和运算符"|"的返回值(Query)作为实参创建qy
b:运算符"<<"会调用query的rep成员,query.rep()调用的是OrQuery的rep(因为初始化对象q时使用的是值是"|"运算符返回的Query,而该对象的智能指针q指向的是一个OrQuery对象),而OrQuery并没有定义rep成员,所以直接使用直接基类BinaryQuery的rep成员
c:由于q的智能指针成员指向的是一个OrQuery对象,所以调用的是OrQuery类的QueryResult eval(const TextQuery &)const;
15.35、15.36
#pragma once #include "12.32.h" #include <algorithm> //set_intersection #include <iterator> //inserter class Query_base { friend class Query; virtual QueryResult eval(const TextQuery &tq)const = 0; virtual std::string rep()const = 0; protected: using line_no = TextQuery::line_no; virtual ~Query_base() = default; }; class Query { friend Query operator~(const Query &qy); friend Query operator|(const Query &lhs, const Query &rhs); friend Query operator&(const Query &lhs, const Query &rhs); std::shared_ptr<Query_base> q; Query(std::shared_ptr<Query_base> qptr) :q(qptr) { std::cout << "Query(std::shared_ptr<Query_base>)\n"; } public: Query(const std::string &s); QueryResult eval(const TextQuery &t)const { q->eval(t); } std::string rep()const { std::cout << "Query rep()\n"; return q->rep(); } }; std::ostream &operator<<(std::ostream &os, const Query query) { return os << query.rep(); } class WordQuery:public Query_base { friend class Query; std::string query_word; WordQuery(const std::string s) :query_word(s) { std::cout << "WordQuery(const std::string s)\n"; } QueryResult eval(const TextQuery &t)const { return t.query(query_word); } std::string rep()const { std::cout << "WordQuery rep()\n"; return query_word; } }; inline Query::Query(const std::string &s) :q(new WordQuery(s)) { std::cout << "Query(const std::string &s)\n"; } class NotQuery :public Query_base { friend Query operator~(const Query &q); Query query; NotQuery(const Query &qy) :query(qy) { std::cout << "NotQuery(const Query &qy)\n"; } std::string rep()const { std::cout << "NotQuery rep()\n"; return "~(" + query.rep() + ")"; } QueryResult eval(const TextQuery &t)const; }; inline Query operator~(const Query &q) { return std::shared_ptr<Query_base>(new NotQuery(q)); } class BinaryQuery :public Query_base { protected: Query lhs, rhs; std::string opSym; BinaryQuery(const Query &l, const Query &r, std::string s) :lhs(l), rhs(r), opSym(s) { std::cout << "BinaryQuery(const Query &l, const Query &r, std::string s)\n"; } std::string rep()const { std::cout << "BinaryQuery rep()\n"; return "(" + lhs.rep + " " + opSym + " " + rhs.rep() + ")"; } }; class AndQuery :public BinaryQuery { friend Query operator&(const Query &lhq, const Query &rhq); AndQuery(const Query &left, const Query &right) :BinaryQuery(left, right, "&") { std::cout << "AndQuery(const Query &left, const Query &right)\n"; } QueryResult eval(const TextQuery &t)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 &lhs, const Query &rhs); OrQuery(const Query &left, const Query &right) :BinaryQuery(left, right, "|") { std::cout << "OrQuery(const Query &left, const Query &right)\n"; } QueryResult eval(const TextQuery &tq)const; }; inline Query operator|(const Query &lhs, const Query &rhs) { return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs)); } QueryResult OrQuery::eval(const TextQuery &tq)const { auto right = rhs.eval(tq), left = lhs.eval(tq); 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 &t)const { auto left = lhs.eval(t), right = rhs.eval(t); auto ret_lines = std::make_shared<std::set<line_no>>(); std::set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));//求出集合A和集合B相同的元素 return QueryResult(rep(), ret_lines, left.get_file()); } QueryResult NotQuery::eval(const TextQuery &t)const { auto result = query.eval(t); auto ret_line = std::make_shared<std::set<line_no>>(); auto beg = result.begin(), end = result.end(); auto sz = result.get_file()->size(); for (size_t n = 0; n != sz; ++n) { if (beg == end || *beg != n) ret_line->insert(n); else if (beg != end) ++beg; } return QueryResult(rep(), ret_line, result.get_file()); }
15.37
题目读不懂,有人做了的请务必回复一下
15.38
a:首先BinaryQuery也属于虚基类,因为没有覆盖Query_base的evalc成员,而且运算符&返回的是一个Query类型,不存在Query到BinaryQuery的转换
b:不存在Query到AndQuery的转换
c:同上,不存在用户定义的从Query到OrQuery的适当转换
15.39
//StrBlob.h #ifndef HEAD1_H_ #define HEAD1_H_ #include <memory> #include <initializer_list> #include <string> #include <vector> class StrBlob { std::shared_ptr<std::vector<std::string>> data; void check(std::vector<std::string>::size_type i, const std::string &msg)const; public: using size_type = std::vector<std::string>::size_type; StrBlob(); StrBlob(std::initializer_list<std::string> il); size_type size()const;//返回vector元素数量 bool empty()const;//是否为空 void push_back(const std::string &t);//添加新元素到尾 void pop_back();//弹出最后一个 std::string front()const; std::string back()const; std::string &front();//返回第一个 std::string &back();//返回最后一个 const std::shared_ptr<std::vector<std::string>> &shared_ptr()const //返回data的const引用 { return data; } }; void StrBlob::check(std::vector<std::string>::size_type i, const std::string &msg)const { if (i >= data->size()) throw std::out_of_range(msg); } StrBlob::StrBlob() :data(std::make_shared<std::vector<std::string>>()) { } StrBlob::StrBlob(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)) { } StrBlob::size_type StrBlob::size()const { return data->size(); } bool StrBlob::empty()const { return data->empty(); } void StrBlob::push_back(const std::string &t) { data->push_back(t); } void StrBlob::pop_back() { check(0, "pop_push on empty StrBlob"); data->pop_back(); } std::string &StrBlob::front() { check(0, "front on empty StrBlob"); return data->front(); } std::string &StrBlob::back() { check(0, "back on empty StrBlob"); return data->back(); } std::string StrBlob::front()const { return data->front(); } std::string StrBlob::back()const { return data->back(); } #endif
//TextQuery.h #ifndef HEAD_H_ #define HEAD_H_ #include "StrBlob.h" #include <iostream> #include <fstream> //ifstream #include <string> #include <vector> #include <sstream> //istringstream #include <map> #include <set> #include <memory> //shared_ptr class QueryResult; class TextQuery { std::shared_ptr<StrBlob> file; //保存整个文件内容,按行分 std::map<std::string, std::shared_ptr<std::set<StrBlob::size_type>>> wm; //每个单词对应行号 public: using line_no = std::vector<std::string>::size_type; TextQuery(std::ifstream &is); QueryResult query(const std::string &s)const; //返回QR,单词、行号set,还有关联到文件内容 }; class QueryResult { friend std::ostream &print(std::ostream &os, const QueryResult &qr); std::string sought; std::shared_ptr<std::set<StrBlob::size_type>> lines; //记录出现的行号 std::shared_ptr<StrBlob> file; //关联到文件内容 public: std::set<StrBlob::size_type>::iterator begin()const { return lines->begin(); } std::set<StrBlob::size_type>::iterator end()const { return lines->end(); } std::shared_ptr<StrBlob> get_file()const { return file; } QueryResult(std::string s,const std::shared_ptr<std::set<StrBlob::size_type>> &p, std::shared_ptr<StrBlob> f) :sought(s), lines(p), file(f){} }; TextQuery::TextQuery(std::ifstream &is) :file(new StrBlob()) //为智能指针file分配空间 { std::string text; while (getline(is, text)) { file->push_back(text); int n = file->size() - 1; std::istringstream line(text); std::string word; while (line >> word) { auto &lines = wm[word]; //如果word在wm中第一次出现,那么对应的set就未分配内存,所以为空 if (!lines) //如果第一次出现 lines.reset(new std::set<StrBlob::size_type>); lines->insert(n); } } } QueryResult TextQuery::query(const std::string &s)const { static std::shared_ptr<std::set<StrBlob::size_type>> nodata(new std::set<StrBlob::size_type>); //当没找到单词时返回 内存常驻 auto loc = wm.find(s); if (loc == wm.end()) return QueryResult(s, nodata, file); else return QueryResult(s, loc->second, file); } std::ostream &print(std::ostream &os, const QueryResult &qr) { os << qr.sought << " occurs " << qr.lines->size() << " " << (qr.lines->size() > 1 ? "times" : "time") << std::endl; for (auto x : *qr.lines) os << "\t(line " << x + 1 << ") " << qr.file->shared_ptr()->at(x) << std::endl; //StrBlob需要添加返回data const引用的方法 return os; } #endif
//Query.h #pragma once #include "TextQuery.h" #include <algorithm> //set_intersection #include <iterator> //inserter class Query_base { friend class Query; virtual QueryResult eval(const TextQuery &tq)const = 0; virtual std::string rep()const = 0; protected: using line_no = TextQuery::line_no; virtual ~Query_base() = default; }; class Query { friend Query operator~(const Query &qy); friend Query operator|(const Query &lhs, const Query &rhs); friend Query operator&(const Query &lhs, const Query &rhs); std::shared_ptr<Query_base> q; Query(std::shared_ptr<Query_base> qptr) :q(qptr) { std::cout << "Query(std::shared_ptr<Query_base>)\n"; } public: Query(const std::string &s); QueryResult eval(const TextQuery &t)const { return q->eval(t); } std::string rep()const { std::cout << "Query rep()\n"; return q->rep(); } }; std::ostream &operator<<(std::ostream &os, const Query query) { return os << query.rep(); } class WordQuery:public Query_base { friend class Query; std::string query_word; WordQuery(const std::string s) :query_word(s) { std::cout << "WordQuery(const std::string s)\n"; } QueryResult eval(const TextQuery &t)const { return t.query(query_word); } std::string rep()const { std::cout << "WordQuery rep()\n"; return query_word; } }; inline Query::Query(const std::string &s) :q(new WordQuery(s)) { std::cout << "Query(const std::string &s)\n"; } class NotQuery :public Query_base { friend Query operator~(const Query &q); Query query; NotQuery(const Query &qy) :query(qy) { std::cout << "NotQuery(const Query &qy)\n"; } std::string rep()const { std::cout << "NotQuery rep()\n"; return "~(" + query.rep() + ")"; } QueryResult eval(const TextQuery &t)const; }; inline Query operator~(const Query &q) { return std::shared_ptr<Query_base>(new NotQuery(q)); } class BinaryQuery :public Query_base { protected: Query lhs, rhs; std::string opSym; BinaryQuery(const Query &l, const Query &r, std::string s) :lhs(l), rhs(r), opSym(s) { std::cout << "BinaryQuery(const Query &l, const Query &r, std::string s)\n"; } std::string rep()const { std::cout << "BinaryQuery rep()\n"; return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; } }; class AndQuery :public BinaryQuery { friend Query operator&(const Query &lhq, const Query &rhq); AndQuery(const Query &left, const Query &right) :BinaryQuery(left, right, "&") { std::cout << "AndQuery(const Query &left, const Query &right)\n"; } QueryResult eval(const TextQuery &t)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 &lhs, const Query &rhs); OrQuery(const Query &left, const Query &right) :BinaryQuery(left, right, "|") { std::cout << "OrQuery(const Query &left, const Query &right)\n"; } QueryResult eval(const TextQuery &tq)const; }; inline Query operator|(const Query &lhs, const Query &rhs) { return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs)); } QueryResult OrQuery::eval(const TextQuery &tq)const { auto right = rhs.eval(tq), left = lhs.eval(tq); 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 &t)const { auto left = lhs.eval(t), right = rhs.eval(t); auto ret_lines = std::make_shared<std::set<line_no>>(); std::set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));//求出集合A和集合B相同的元素 return QueryResult(rep(), ret_lines, left.get_file()); } QueryResult NotQuery::eval(const TextQuery &t)const { auto result = query.eval(t); auto ret_line = std::make_shared<std::set<line_no>>(); auto beg = result.begin(), end = result.end(); auto sz = result.get_file()->size(); for (size_t n = 0; n != sz; ++n) { if (beg == end || *beg != n) ret_line->insert(n); else if (beg != end) ++beg; } return QueryResult(rep(), ret_line, result.get_file()); }
#include "Query.h" int main(int argc, char **argv) { using namespace std; ifstream ifile(argv[1]); print(cout, (Query("is")&Query("and")).eval(ifile)) << endl; system("pause"); return 0; }
如果rhs是空集,那么内容到lhs
如果lhs是空集,那么内容为rhs
如果都为空集,那么内容为空
15.41