练习15.1
成员函数应在其声明之前动态绑定。
基类中的虚成员希望其派生类定义其自己的版本。特别是基类通常应定义虚析构函数,即使它不起作用。
练习15.2
派生类能访问基类的共有成员而不能访问私有成员,但派生类能访问基类的protected访问运算符描述的成员,而禁止其它用户访问
练习15.3
#include <string> #include <iostream> #ifndef _QUOTE_H_ #define _QUOTE_H_ class Quote { 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; private: std::string bookNo; protected: double price = 0.0; }; double print_total(std::ostream& os, const Quote& item, size_t n) { double ret = item.net_price(n); os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl; return ret; } #endif // !_QUOTE_H_
练习15.4
class Base { ... }; (a) class Derived : public Derived { ... }; // 错误,类重复定义,不能自己继承自己 (b) class Derived : private Base { ... }; // 正确 (c) class Derived : public Base; // 错误,类的声明包含类名但不包含类派生列表
练习15.5
class Bulk_quote:public Quote { public: Bulk_quote() = default; Bulk_quote(const std::string&, double, std::size_t,double); double net_price(std::size_t)const override; protected: std::size_t min_qty = 0; double discount = 0.0; }; Bulk_quote::Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Quote(book, p), min_qty(qty), discount(disc) {} inline double Bulk_quote::net_price(std::size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; }
练习15.6
int main(int argc, char* argv[]) { Bulk_quote bq; Quote q(bq); print_total(cout, q, 1); print_total(cout, bq, 1); return 0; }
练习15.7
class Limit_quote : public Bulk_quote { public: Limit_quote() = default; Limit_quote(const std::string&, double, std::size_t, std::size_t, double); double net_price(std::size_t)const override; private: std::size_t max_qty = 0; }; Limit_quote::Limit_quote(const std::string& book, double p, std::size_t min, std::size_t max, double disc) :Bulk_quote(book, p,min,disc), max_qty(max){} inline double Limit_quote::net_price(std::size_t cnt) const { if(cnt>=max_qty) return max_qty * (1 - discount) * price+(cnt- max_qty)*price; else if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; }
练习15.8
静态类型:在编译时总是已知的,它是变量声明时的类型或表达式生成的类型
动态类型:变量或表达式表示的内存中的对象的类型。知道运行时才可知
练习15.9
基类的指针或引用的静态类型可能与其动态类型不一致。
如第527页形参item执行的静态类型是Quote&,但是传入的实参是Bulk_Quote对象,那么静态类型和动态类型就不一致
练习15.10
fstream继承了iostream 类型的行为,因此,ifstream可以使用read函数
练习15.11
#include <string> #include <iostream> #ifndef _QUOTE_H_ #define _QUOTE_H_ class Quote { 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; virtual void debug() { cout << "bookNo:" << bookNo << " price:" << price << endl; } private: std::string bookNo; protected: double price = 0.0; }; double print_total(std::ostream& os, const Quote& item, size_t n) { double ret = item.net_price(n); os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl; return ret; } class Bulk_quote:public Quote { public: Bulk_quote() = default; Bulk_quote(const std::string&, double, std::size_t,double); double net_price(std::size_t)const override; void debug()override { cout << "min_qty:" << min_qty << " discount:" << discount << endl; } protected: std::size_t min_qty = 0; double discount = 0.0; }; Bulk_quote::Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Quote(book, p), min_qty(qty), discount(disc) {} inline double Bulk_quote::net_price(std::size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; } class Limit_quote : public Bulk_quote { public: Limit_quote() = default; Limit_quote(const std::string&, double, std::size_t, std::size_t, double); double net_price(std::size_t)const override; void debug()override { cout << "max_qty:" << max_qty << endl; } private: std::size_t max_qty = 0; }; Limit_quote::Limit_quote(const std::string& book, double p, std::size_t min, std::size_t max, double disc) :Bulk_quote(book, p,min,disc), max_qty(max){} inline double Limit_quote::net_price(std::size_t cnt) const { if(cnt>=max_qty) return max_qty * (1 - discount) * price+(cnt- max_qty)*price; else if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; } #endif // !_QUOTE_H_
练习15.12
有必要,overrride关键字是用来说明派生类中的虚函数,并让编译器能够判断出该函数是否覆盖了已存在的函数,而final则是让之后任何尝试覆盖该函数的操作都引起错误
练习15.13
class base { public: string name() { return basename; } virtual void print(ostream& os) { os << basename; }//将os绑定到一个iostream或者是iostream的输入流中,并向输入流传入成员basename private: string basename; }; class derived : public base { public: //void print(ostream& os) { print(os); os << " " << i; }重写base类的print函数,并且在其中调用base的print(os),但是由于没有加::范围限定符,导致其调用的还是derived的print函数,造成无限递归。 void print(ostream& os) { base::print(os); os << " " << i; }//在函数体内加入范围限定符 private: int i; };
练习15.14
base bobj; base *bp1 = &bobj; base &br1 = bobj; derived dobj; base *bp2 = &dobj; base &br2 = dobj; (a)bobj.print(); // base::print() (b)dobj.print(); // derived::print() (c)bp1->name(); // base::name() (d)bp2->name(); // base::name() (e)br1.print(); // base::print() (f)br2.print(); // derived::print()
练习15.15
class Disc_Quote :public Quote { public: Disc_Quote() = default; Disc_Quote(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)const = 0; protected: std::size_t quantity = 0; double discount = 0.0; }; class Bulk_quote:public Disc_Quote { public: Bulk_quote() = default; Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Disc_Quote(book, p, qty, disc) {} double net_price(std::size_t)const override; void debug()override { cout << "min_qty:" << min_qty << " discount:" << discount << endl; } protected: std::size_t min_qty = 0; double discount = 0.0; }; inline double Bulk_quote::net_price(std::size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; }
练习15.16
class Limit_quote : public Disc_Quote { public: Limit_quote() = default; Limit_quote(const std::string&, double, std::size_t, std::size_t, double); double net_price(std::size_t)const override; void debug()override { cout << "max_qty:" << max_qty << endl; } private: std::size_t max_qty = 0; }; Limit_quote::Limit_quote(const std::string& book, double p, std::size_t min, std::size_t max, double disc) :Disc_Quote(book, p,min,disc), max_qty(max){} inline double Limit_quote::net_price(std::size_t cnt) const { if(cnt>=max_qty) return max_qty * (1 - discount) * price+(cnt- max_qty)*price; else if (cnt >= quantity) return cnt * (1 - discount) * price; else return cnt * price; }
练习15.17
factMain.cpp(297): error C2259: “Disc_Quote”: 无法实例化抽象类
C:Users王威source
eposProject5Quote.h(27): note: 参见“Disc_Quote”的声明
factMain.cpp(297): note: 由于下列成员:
factMain.cpp(297): note: “double Disc_Quote::net_price(size_t) const”: 是抽象的
C:Users王威source
eposProject5Quote.h(34): note: 参见“Disc_Quote::net_price”的声明
练习15.18
Base *p = &d1; // d1的类型是Pub_Derv,合法 p = &d2; // d2的类型是Priv_Derv,非法,保护继承,派生类不能向基类转换 p = &d3; // d3的类型是Prot_Derv,非法,私有继承,则派生类不能向基类转换 p = &dd1; // dd1的类型是Derived_from_Public,合法 p = &dd2; // dd2的类型是Derived_from_Private,非法,Priv_Derv的派生类无法执行类的访问 p = &dd3; // dd3的类型是Derived_from_Protected,非法,保护继承,派生类不能向基类转换
练习15.19
Pub_Derv d1; // 合法 Priv_Derv d2; // 合法 Prot_Derv d3; // 合法 Derived_from_Public dd1; // 合法 Derived_from_Private dd2; // 不合法 Derived_from_Protected dd3; // 合法
练习15.20
class Base { public: void pub_mem(); protected: int prot_mem(); private: char priv_mem(); }; struct Pub_Derv : public Base { int f() { return prot_mem(); } void memfcn(Base& b) { b = *this; } }; struct Pro_Derv : protected Base { int f() { return prot_mem(); } void memfcn(Base& b) { b = *this; } }; struct Priv_Derv : private Base { int f1() { return prot_mem(); } void memfcn(Base& b) { b = *this; } }; struct Derived_from_Public : public Pub_Derv { int use_base() { return prot_mem(); } void memfcn(Base& b) { b = *this; } }; struct Derived_from_Pro : public Pro_Derv { void memfcn(Base &b) { b = *this; } }; struct Derived_from_Private : public Priv_Derv { // void memfcn(Base &b) { b = *this; } }; int main(int argc, char* argv[]) { Pub_Derv d1; Priv_Derv d2; Pro_Derv d3; Derived_from_Public dd1; Derived_from_Pro dd2; Derived_from_Private dd3; Base* p = &d1; d1.memfcn(*p); d2.memfcn(*p); d3.memfcn(*p); dd1.memfcn(*p); dd2.memfcn(*p); dd3.memfcn(*p); //p = &d2; //p = &d3; p = &dd1; //p = &dd2; //p = &dd3; return 0; }
练习15.21
练习15.22
#ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ class Graphics { public: Graphics()=default; Graphics(size_t x, size_t y):x_(x),y_(y){} virtual const char* Graphics_name() = 0; virtual double size() const = 0; virtual size_t get_dimension() const = 0; ~Graphics() = default; protected: size_t x_ = 0; size_t y_ = 0; }; class gif:public Graphics { public: gif() = default; gif(size_t x, size_t y,size_t d):Graphics(), dimension(d){} ~gif() = default; const char* Graphics_name() override{ return "gif"; } double size() const override { return (x_ * y_ * dimension); } size_t get_dimension() const override { return dimension; } protected: size_t dimension; }; class jpeg:public Graphics { public: jpeg() = default; jpeg(size_t x, size_t y, size_t d) :Graphics(), dimension(d) {} ~jpeg() = default; const char* Graphics_name() override { return "jpeg"; } double size() const override {} size_t get_dimension() const override {} protected: size_t dimension; }; class tiff:public Graphics { public: tiff() = default; tiff(size_t x, size_t y, size_t d) :Graphics(), dimension(d) {} ~tiff() = default; const char* Graphics_name() override { return "tiff"; } double size() const override {} size_t get_dimension() const override {} protected: size_t dimension; }; class bmp:public Graphics { public: bmp() = default; bmp(size_t x, size_t y, size_t d) :Graphics(), dimension(d) {} ~bmp()=default; const char* Graphics_name() override { return "bmp"; } double size() const override {} size_t get_dimension() const override {} protected: size_t dimension; }; #endif // !_GRAPHICS_H_
练习15.23
class Base { public: virtual int fcn() { cout << "Base::fun()" << endl; return 0; } }; class D1:public Base { public: int fcn(int i) { cout << "D1::fun(int)" << endl; return 0; } int fcn()override { cout << "D1::fun()" << endl; return 0; } virtual void f2() { cout << "D1::f2()" << endl; } }; class D2:public D1 { public: int fcn(int i) { cout << "D2::fun(int)" << endl; return 0; } int fcn()override { cout << "D2::fun()" << endl; return 0; } void f2() { cout << "D2::f2()" << endl; } }; int main(int argc, char* argv[]) { Base bobj; D1 d1obj; D2 d2obj; Base* bp1 = &bobj, * bp2 = &d1obj, * bp3 = &d2obj; bp1->fcn();//Base::fun() bp2->fcn();//D1::fun() bp3->fcn();//D2::fun() D1* d1p = &d1obj; D2* d2p = &d2obj; //bp2->f2(); d1p->f2();//D1::f2() d2p->f2();//D2::f2() }
练习15.24
基类因为被其他需要虚析构函数。虚析构函数解决基类的指针指向派生类对象,并用基类的指针删除派生类对象的情况
练习15.25
error C2280: “Bulk_quote::Bulk_quote(void)”: 尝试引用已删除的函数 note: 参见“Bulk_quote::Bulk_quote”的声明 note: “Bulk_quote::Bulk_quote(void)”: 由于 基类“Disc_Quote”不具备相应的 默认构造函数 或重载解决不明确,因此已隐式删除函数 note: 参见“Disc_Quote”的声明
因为Disc_quote有自定义的构造函数,如果不显示声明,编译器不会再生成默认构造函数,这将阻止其子类生成默认构造函数,因此基类的默认构造函数应该显式声明,以便子类在执行默认构造函数的时候调用。
练习15.26
#include <string> #include <iostream> #ifndef _QUOTE_H_ #define _QUOTE_H_ class Quote { 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){ cout << "Quote(const Quote& q)" << endl; } Quote(Quote&& q)noexcept :bookNo(std::move(q.bookNo)), price(std::move(q.price)) { cout << "Quote(Quote&& q)" << endl; } Quote& operator=(const Quote& rhs) { cout << "Quote& operator=(const Quote& rhs)" << endl; price = rhs.price; bookNo = rhs.bookNo; return *this; } Quote& operator=(Quote&& rhs)noexcept { cout << "Quote& operator=(Quote&& rhs)" << endl; price = std::move(rhs.price); bookNo = std::move(rhs.bookNo); return *this; } std::string isbn() const { return bookNo; } virtual double net_price(std::size_t n)const { return n * price; } virtual ~Quote() = default; virtual void debug() { cout << "bookNo:" << bookNo << " price:" << price << endl; } private: std::string bookNo; protected: double price = 0.0; }; double print_total(std::ostream& os, const Quote& item, size_t n) { double ret = item.net_price(n); os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl; return ret; } class Disc_Quote :public Quote { public: Disc_Quote() = default; Disc_Quote(const std::string& book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) {} Disc_Quote(const Disc_Quote& dq) :Quote(dq), quantity(dq.quantity), discount(dq.discount){ cout << "Disc_Quote(const Disc_Quote& dq)" << endl; } Disc_Quote(Disc_Quote&& dq)noexcept :Quote(std::move(dq)), quantity(std::move(dq.quantity)), discount(std::move(dq.discount)) { cout << "Disc_Quote(Disc_Quote&& dq)" << endl; } Disc_Quote& operator=(const Disc_Quote& rhs) { cout << "Disc_Quote& operator=(const Disc_Quote& rhs)" << endl; Quote::operator=(rhs); quantity = rhs.quantity; discount = rhs.discount; return *this; } Disc_Quote& operator=(Disc_Quote&& rhs)noexcept { cout << "Disc_Quote& operator=(Disc_Quote&& rhs)" << endl; Quote::operator=(std::move(rhs)); quantity = std::move(rhs.quantity); discount = std::move(rhs.discount); return *this; } double net_price(std::size_t)const = 0; protected: std::size_t quantity = 0; double discount = 0.0; }; class Bulk_quote:public Disc_Quote { public: Bulk_quote() = default; Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Disc_Quote(book, p, qty, disc) {} Bulk_quote(const Bulk_quote& bq) :Disc_Quote(bq), min_qty(bq.min_qty){ cout << "Bulk_quote(const Bulk_quote& bq)" << endl; } Bulk_quote(Bulk_quote&& bq) noexcept :Disc_Quote(std::move(bq)), min_qty(std::move(bq.min_qty)) { cout << "Bulk_quote(Bulk_quote&& bq)" << endl; } Bulk_quote& operator=(const Bulk_quote& rhs) { cout << "Bulk_quote& operator=(const Bulk_quote& rhs)" << endl; Disc_Quote::operator=(rhs); min_qty = rhs.min_qty; return *this; } Bulk_quote& operator=(Bulk_quote&& rhs) noexcept { cout << "Bulk_quote& operator=(Bulk_quote&& rhs)" << endl; Disc_Quote::operator=(std::move(rhs)); min_qty = std::move(rhs.min_qty); return *this; } double net_price(std::size_t)const override; void debug()override { cout << "min_qty:" << min_qty << " discount:" << discount << endl; } protected: std::size_t min_qty = 0; }; inline double Bulk_quote::net_price(std::size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; } class Limit_quote : public Disc_Quote { public: Limit_quote() = default; Limit_quote(const std::string&, double, std::size_t, std::size_t, double); Limit_quote(const Limit_quote& lq) :Disc_Quote(lq), max_qty(lq.max_qty) { cout << "Limit_quote(const Limit_quote& lq)" << endl; } Limit_quote(Limit_quote&& lq) noexcept :Disc_Quote(std::move(lq)), max_qty(std::move(lq.max_qty)) { cout << "Limit_quote(Limit_quote&& lq)" << endl; } Limit_quote& operator=(const Limit_quote& rhs) { cout << "Limit_quote& operator=(const Limit_quote& rhs)" << endl; Disc_Quote::operator=(rhs); max_qty = rhs.max_qty; return *this; } Limit_quote& operator=(Limit_quote&& rhs)noexcept { cout << "Limit_quote& operator=(Limit_quote&& rhs)" << endl; Disc_Quote::operator=(std::move(rhs)); max_qty = std::move(rhs.max_qty); return *this; } double net_price(std::size_t)const override; void debug()override { cout << "max_qty:" << max_qty << endl; } private: std::size_t max_qty = 0; }; Limit_quote::Limit_quote(const std::string& book, double p, std::size_t min, std::size_t max, double disc) :Disc_Quote(book, p,min,disc), max_qty(max){} inline double Limit_quote::net_price(std::size_t cnt) const { if(cnt>=max_qty) return max_qty * (1 - discount) * price+(cnt- max_qty)*price; else if (cnt >= quantity) return cnt * (1 - discount) * price; else return cnt * price; } #endif // !_QUOTE_H_
练习15.27
#include <string> #include <iostream> #ifndef _QUOTE_H_ #define _QUOTE_H_ class Quote { 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){ cout << "Quote(const Quote& q)" << endl; } Quote(Quote&& q)noexcept :bookNo(std::move(q.bookNo)), price(std::move(q.price)) { cout << "Quote(Quote&& q)" << endl; } Quote& operator=(const Quote& rhs) { cout << "Quote& operator=(const Quote& rhs)" << endl; price = rhs.price; bookNo = rhs.bookNo; return *this; } Quote& operator=(Quote&& rhs)noexcept { cout << "Quote& operator=(Quote&& rhs)" << endl; price = std::move(rhs.price); bookNo = std::move(rhs.bookNo); return *this; } std::string isbn() const { return bookNo; } virtual double net_price(std::size_t n)const { return n * price; } virtual ~Quote() = default; virtual void debug() { cout << "bookNo:" << bookNo << " price:" << price << endl; } private: std::string bookNo; protected: double price = 0.0; }; double print_total(std::ostream& os, const Quote& item, size_t n) { double ret = item.net_price(n); os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl; return ret; } class Disc_Quote :public Quote { public: Disc_Quote() = default; Disc_Quote(const std::string& book, double price, std::size_t qty, double disc) :Quote(book, price), quantity(qty), discount(disc) {} Disc_Quote(const Disc_Quote& dq) :Quote(dq), quantity(dq.quantity), discount(dq.discount){ cout << "Disc_Quote(const Disc_Quote& dq)" << endl; } Disc_Quote(Disc_Quote&& dq)noexcept :Quote(std::move(dq)), quantity(std::move(dq.quantity)), discount(std::move(dq.discount)) { cout << "Disc_Quote(Disc_Quote&& dq)" << endl; } Disc_Quote& operator=(const Disc_Quote& rhs) { cout << "Disc_Quote& operator=(const Disc_Quote& rhs)" << endl; Quote::operator=(rhs); quantity = rhs.quantity; discount = rhs.discount; return *this; } Disc_Quote& operator=(Disc_Quote&& rhs)noexcept { cout << "Disc_Quote& operator=(Disc_Quote&& rhs)" << endl; Quote::operator=(std::move(rhs)); quantity = std::move(rhs.quantity); discount = std::move(rhs.discount); return *this; } double net_price(std::size_t)const = 0; protected: std::size_t quantity = 0; double discount = 0.0; }; class Bulk_quote:public Disc_Quote { public: using Disc_Quote::Disc_Quote; /*Bulk_quote() = default; Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Disc_Quote(book, p, qty, disc) {} Bulk_quote(const Bulk_quote& bq) :Disc_Quote(bq), min_qty(bq.min_qty){ cout << "Bulk_quote(const Bulk_quote& bq)" << endl; } Bulk_quote(Bulk_quote&& bq) noexcept :Disc_Quote(std::move(bq)), min_qty(std::move(bq.min_qty)) { cout << "Bulk_quote(Bulk_quote&& bq)" << endl; } Bulk_quote& operator=(const Bulk_quote& rhs) { cout << "Bulk_quote& operator=(const Bulk_quote& rhs)" << endl; Disc_Quote::operator=(rhs); min_qty = rhs.min_qty; return *this; } Bulk_quote& operator=(Bulk_quote&& rhs) noexcept { cout << "Bulk_quote& operator=(Bulk_quote&& rhs)" << endl; Disc_Quote::operator=(std::move(rhs)); min_qty = std::move(rhs.min_qty); return *this; }*/ double net_price(std::size_t)const override; void debug()override { cout << "min_qty:" << min_qty << " discount:" << discount << endl; } protected: std::size_t min_qty = 0; }; inline double Bulk_quote::net_price(std::size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; } class Limit_quote : public Disc_Quote { public: Limit_quote() = default; Limit_quote(const std::string&, double, std::size_t, std::size_t, double); Limit_quote(const Limit_quote& lq) :Disc_Quote(lq), max_qty(lq.max_qty) { cout << "Limit_quote(const Limit_quote& lq)" << endl; } Limit_quote(Limit_quote&& lq) noexcept :Disc_Quote(std::move(lq)), max_qty(std::move(lq.max_qty)) { cout << "Limit_quote(Limit_quote&& lq)" << endl; } Limit_quote& operator=(const Limit_quote& rhs) { cout << "Limit_quote& operator=(const Limit_quote& rhs)" << endl; Disc_Quote::operator=(rhs); max_qty = rhs.max_qty; return *this; } Limit_quote& operator=(Limit_quote&& rhs)noexcept { cout << "Limit_quote& operator=(Limit_quote&& rhs)" << endl; Disc_Quote::operator=(std::move(rhs)); max_qty = std::move(rhs.max_qty); return *this; } double net_price(std::size_t)const override; void debug()override { cout << "max_qty:" << max_qty << endl; } private: std::size_t max_qty = 0; }; Limit_quote::Limit_quote(const std::string& book, double p, std::size_t min, std::size_t max, double disc) :Disc_Quote(book, p,min,disc), max_qty(max){} inline double Limit_quote::net_price(std::size_t cnt) const { if(cnt>=max_qty) return max_qty * (1 - discount) * price+(cnt- max_qty)*price; else if (cnt >= quantity) return cnt * (1 - discount) * price; else return cnt * price; } #endif // !_QUOTE_H_
练习15.28
int main(int argc, char* argv[]) { double sum = 0; Bulk_quote bq; vector<std::shared_ptr<Quote>> basket; basket.emplace_back(std::make_shared<Bulk_quote>("0-201-54848-8", 50, 10, .25)); basket.emplace_back(std::make_shared<Bulk_quote>("0-201-54848-8", 40, 10, .25)); for (auto i : basket) { sum+=i->net_price(15); } cout << sum; }
练习15.29
int main(int argc, char* argv[]) { double sum = 0; Bulk_quote bq; vector<std::shared_ptr<Quote>> basket; basket.emplace_back(std::make_shared<Quote>("0-201-54848-8", 50)); basket.emplace_back(std::make_shared<Quote>("0-201-54848-8", 40)); for (auto i : basket) { sum+=i->net_price(15); } cout << sum; }
不一致,因为两次代码传入的对象的类型不同,调用的net_price()属于不同类
练习15.30
#include <set> #include "Quote.h" #ifndef _BASKET_H_ #define _BASKET_H_ 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&)const; 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 }; }; double Basket::total_receipt(std::ostream&os) const { double sum = 0.0; for (auto 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; } #endif // !_BASKET_H_
练习15.31
(a)WordQuery OrQuery AndQuery NotQuery Query
(b)WordQuery OrQuery AndQuery NotQuery Query
(c)WordQuery OrQuery AndQuery Query
练习15.32
拷贝:当Query对象被拷贝时,会调用合成的拷贝构造函数。拷贝类的成员,智能指针q引用计数加1
移动:当Query对象被移动时,会调用合成移动构造函数,移动类的成员,新对象的智能指针q的引用计数加1,原对象的智能指针q的引用计数减1。
赋值:当Query对象被移动时,会调用合成的赋值函数,结果与拷贝操作相同
销毁:当Query对象被移动时,会调用合成的析构函数,智能指针q引用计数减1
练习15.33
当Query_base对象被拷贝,移动,赋值,销毁时,由于没有需要分配内存的数据成员,所以可以使用合成的函数,又由于Query_base是抽象类,所以发生拷贝、移动、赋值或销毁时,操作的其实是它对应类型的子类。
练习15.34
(a)
Query::Query(const std::string&) 传入参数分别为"fiery"、“bird”、“wind”
WordQuery::WordQuery(const std::string&) 传入参数分别为"fiery"、“bird”、“wind”
BinartQuery::BinartQuery(const Query &l,const Query& r,std::string s)
AndQuery::AndQuery(const Query &l,const Query& r)
BinartQuery::BinartQuery(const Query &l,const Query& r,std::string s)
OrQuery::OrQuery(const Query &l,const Query& r)
Query::Query (std::shared_ptr<Query_base> query)
(b)
在operator<<中调用的是Query的rep;
又由于Query是继承了Query_Base类的rep,由于生成对象q调用的是”|“运算返回的Query,所以实际调用的是OrQuery的rep,但是OrQrery是继承了BinaryQuery的rep函数,所以实际调用的是BinaryQuery的rep函数;
BinaryQuery的lhs调用的是”&“运算返回的Query,和上面相似,实际调用的是BinaryQuery的rep函数,BinaryQuery的rhs调用的是Word_Query中的rep;
Binary_Query中的rep调用的是Word_Query中的rep
(c)
Query中的eval调用的是Query_base中的eval。
但这里Query_base指向的是OrQuery,所以调用的是OrQuery中的eval。
练习15.35
练习15.36
#ifndef _QUERY_H_ #define _QUERY_H_ #include "TextQuery.h" 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; }; 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 { std::cout << "QueryResult::rep" << std::endl; 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; WordQuery(const std::string& s) :query_word(s) { std::cout << "WordQuery::WordQuery" << std::endl; } QueryResult eval(const TextQuery& t)const { return t.query(query_word); } std::string rep()const { std::cout << "WordQuery::rep" << std::endl; return query_word; } std::string query_word; }; Query::Query(const std::string&s):q(new WordQuery(s)){ std::cout << "Query::Query" << std::endl; } class NotQuery:public Query_base { friend Query operator~(const Query&); NotQuery(const Query &q):query(q){ std::cout << "NotQuery::NotQuery" << std::endl; } std::string rep()const { std::cout << "NotQuery::rep" << std::endl; 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)); } QueryResult NotQuery::eval(const TextQuery& text) const { auto result = query.eval(text); auto ret_lines = std::make_shared<set<size_t>>(); 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_lines->insert(n); else if (beg != end) ++beg; } string s = rep(); return QueryResult(s, ret_lines, result.get_file()); } class BinaryQuery :public Query_base { protected: BinaryQuery(const Query& l, const Query& r, std::string s) :lhs(l), rhs(r), opSym(s) { std::cout << "BinaryQuery::BinaryQuery" << std::endl; } std::string rep() const { std::cout << "BinaryQuery::rep" << std::endl; return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; } 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, "&") { std::cout << "AndQuery::AndQuery" << std::endl; } QueryResult eval(const TextQuery&) const; }; inline Query operator& (const Query& lhs, const Query& rhs) { return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs)); } QueryResult AndQuery::eval(const TextQuery& text) const { auto right = rhs.eval(text), left = lhs.eval(text); auto ret_lines = std::make_shared<set<size_t>>(); set_intersection(left.begin(), left.end(),right.begin(), right.end(),inserter(*ret_lines,ret_lines->begin())); string s = rep(); return QueryResult(s, ret_lines, left.get_file()); } class OrQuery : public BinaryQuery { friend Query operator| (const Query&, const Query&); OrQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "|"){ std::cout << "OrQuery::OrQuery" << std::endl; } QueryResult eval(const TextQuery&) 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& text) const { auto right = rhs.eval(text), left = lhs.eval(text); auto ret_lines = std::make_shared<set<size_t>>(left.begin(), left.end()); ret_lines->insert(right.begin(), right.end()); string s = rep(); return QueryResult(s, ret_lines, left.get_file()); } std::ostream& operator<<(std::ostream& os,const Query &query) { return os << query.rep(); } #endif // !_QUERY_H_
int main(int argc, char* argv[]) { Query q = Query("firey") & Query("bird") | Query("wind"); cout << q; }
打印结果
WordQuery::WordQuery
Query::Query
WordQuery::WordQuery
Query::Query
WordQuery::WordQuery
Query::Query
BinaryQuery::BinaryQuery
AndQuery::AndQuery
BinaryQuery::BinaryQuery
OrQuery::OrQuery
QueryResult::rep
BinaryQuery::rep
QueryResult::rep
WordQuery::rep
QueryResult::rep
BinaryQuery::rep
QueryResult::rep
WordQuery::rep
QueryResult::rep
WordQuery::rep
练习15.37
不需要做出改变
练习15.38
BinaryQuery a = Query("firey") & Query("bird");// 不合法,因为BinaryQuery是一个抽象基类,不能创建BinaryQuery类型的对象 AndQuery b = Query("firry") & Query("bird");// 不合法,因为&操作返回的是Query操作,而Query不能转化为AndQuery OrQuery c = Query("firey") & Query("bird");// 不合法,因为&操作返回的是Query操作,而Query不能转化为OrQuery
练习15.39
参考练习15.37
((firey & bird) | wind)
练习15.40
如果rhs是空集,那么内容到lhs
如果lhs是空集,那么内容为rhs
如果都为空集,那么内容为空
练习15.41
#ifndef _QUERY_H_ #define _QUERY_H_ #include "TextQuery.h" class Query; 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; }; 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& query) :q(query.q), uc(query.uc) {} QueryResult eval(const TextQuery& t)const { return q->eval(t); } std::string rep()const { std::cout << "QueryResult::rep" << std::endl; return q->rep(); } ~Query(); private: //Query(std::shared_ptr<Query_base> query) :q(query) {} //std::shared_ptr<Query_base> q; Query(Query_base* query) : q(query), uc(new int(1)) { } Query_base* q; int* uc; }; class WordQuery:public Query_base { friend class Query; WordQuery(const std::string& s) :query_word(s) { std::cout << "WordQuery::WordQuery" << std::endl; } QueryResult eval(const TextQuery& t)const { return t.query(query_word); } std::string rep()const { std::cout << "WordQuery::rep" << std::endl; return query_word; } std::string query_word; }; Query::Query(const string& s) : q(new WordQuery(s)), uc(new int(1)) { std::cout << "Query::Query" << std::endl; } inline Query::~Query() { if (-- * uc == 0) { delete q; delete uc; } } class NotQuery:public Query_base { friend Query operator~(const Query&); NotQuery(const Query &q):query(q){ std::cout << "NotQuery::NotQuery" << std::endl; } std::string rep()const { std::cout << "NotQuery::rep" << std::endl; return"~(" + query.rep() + ")"; } QueryResult eval(const TextQuery&)const; Query query; }; inline Query operator~(const Query& operand) { return new NotQuery(operand); } QueryResult NotQuery::eval(const TextQuery& text) const { auto result = query.eval(text); auto ret_lines = std::make_shared<set<size_t>>(); 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_lines->insert(n); else if (beg != end) ++beg; } string s = rep(); return QueryResult(s, ret_lines, result.get_file()); } class BinaryQuery :public Query_base { protected: BinaryQuery(const Query& l, const Query& r, std::string s) :lhs(l), rhs(r), opSym(s) { std::cout << "BinaryQuery::BinaryQuery" << std::endl; } std::string rep() const { std::cout << "BinaryQuery::rep" << std::endl; return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; } 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, "&") { std::cout << "AndQuery::AndQuery" << std::endl; } QueryResult eval(const TextQuery&) const; }; inline Query operator& (const Query& lhs, const Query& rhs) { return new AndQuery(lhs, rhs); } QueryResult AndQuery::eval(const TextQuery& text) const { auto right = rhs.eval(text), left = lhs.eval(text); auto ret_lines = std::make_shared<set<size_t>>(); set_intersection(left.begin(), left.end(),right.begin(), right.end(),inserter(*ret_lines,ret_lines->begin())); string s = rep(); return QueryResult(s, ret_lines, left.get_file()); } class OrQuery : public BinaryQuery { friend Query operator| (const Query&, const Query&); OrQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "|"){ std::cout << "OrQuery::OrQuery" << std::endl; } QueryResult eval(const TextQuery&) const; }; inline Query operator| (const Query& lhs, const Query& rhs) { return new OrQuery(lhs, rhs); } QueryResult OrQuery::eval(const TextQuery& text) const { auto right = rhs.eval(text), left = lhs.eval(text); auto ret_lines = std::make_shared<set<size_t>>(left.begin(), left.end()); ret_lines->insert(right.begin(), right.end()); string s = rep(); return QueryResult(s, ret_lines, left.get_file()); } std::ostream& operator<<(std::ostream& os,const Query &query) { return os << query.rep(); } #endif // !_QUERY_H_
练习15.42
inline TextQuery::TextQuery(ifstream& ifs) : text(std::make_shared<StrVec>()), query_words(std::make_shared<map<string, std::shared_ptr<set<size_t>>>>()) { size_t size=0; if (ifs) { for (string line; getline(ifs, line,'.'); ++size) { text->push_back(line); istringstream iss(line); size = text->size(); for (string text, word; iss >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); // use reference avoid count of shared_ptr add. auto& nos = (*query_words)[word]; if (!nos) nos.reset(new std::set<size_t>); nos->insert(size); } } } }