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);
            }
        }
    }
}
原文地址:https://www.cnblogs.com/GodZhuan/p/14045517.html