C++ Primer第5版 第十五章课后练习答案
合集《C++ Primer第5版》 课后练习答案 - 丸子球球 - 博客园 (cnblogs.com)
练习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;
}
练习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;
}
练习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();
练习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\repos\Project5\Quote.h(27): note: 参见“Disc_Quote”的声明
factMain.cpp(297): note: 由于下列成员:
factMain.cpp(297): note: “double Disc_Quote::net_price(size_t) const”: 是抽象的
C:\Users\王威\source\repos\Project5\Quote.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;
练习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;
};
练习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”不具备相应的 默认构造函数 或重载解决不明确,因此已隐式删除函数
因为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;
}
练习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;
}
练习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;
}
练习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(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();
}
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<br>
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("firry") & 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) {*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();
}
练习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);
}
}
}
}