zoukankan      html  css  js  c++  java
  • C++ Primer第5版 第十五章课后练习答案

    练习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);
                }
            }
        }
    }
  • 相关阅读:
    H5页面跳到安卓APP和iosAPP
    JS location.href传参及接受参数
    获取当前日期及对应星期
    前端获取当前一周时间 数组形式
    Java基础(四) Object 数组转成 String 数组
    定时任务cron表达式详解
    jquery如何删除数组中的一个元素?
    Mybatis Mapper.xml 需要查询返回List<String>
    oracle的 listagg() WITHIN GROUP () 行转列函数的使用
    如何修改Oracle中表的字段长度?
  • 原文地址:https://www.cnblogs.com/GodZhuan/p/14045517.html
Copyright © 2011-2022 走看看