本文答案,部分参考于C++ Primer 习题集
前面章节的习题答案
配套的学习资料
https://www.jianguoyun.com/p/DTK5uJgQldv8CBjKv80D
15.1
在类中被声明为virtual的成员.基类都希望这种成员在派生类中重定义,除了构造函数之外.任意非static成员都可以为虚成员.
15.2
proteceted为受保护的访问标号.protected成员可以被该类的成员.友元和派生类成员(非友元)访问,而不可以被该类型的普通用户访问.而private成员只能被基类的成员和友元访问.派生类不能访问.
15.3
class Quote {
public:
Quote() = default;
Quote(const string& book, double sales_price) : bookNo(book), price(sales_price) {}
string isbn() const { return bookNo; }
//返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual double net_price(size_t n)const { return n * price; }
virtual ~Quote() = default;
private:
string bookNo; //书籍的ISBN编号
protected:
double price = 0.0; //代表普通状态下不打折的价格
};
double print_total(ostream& os, const Quote& item, size_t n) {
//根据传入item形参的对象类型调用Quote::net_price
//或者Bulk_quote::net_price
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold:" << n << " total due:" << ret << endl;
return ret;
}
15.4
(a) 错误,不能用类本身作为类的基类.
© 声明类时,不可以包含派生列表
15.5
class Bulk_quote :public Quote {
public:
double net_price(size_t cnt) const override {
if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
private:
size_t min_qty;
double discount;
};
15.6
略
15.7
class Limited_quote :public Quote {
public:
double net_price(size_t cnt) const override {
if (cnt <= min_qty) return cnt * (1 - discount) * price;
else return min_qty * (1 - discount) * price + (cnt - min_qty) * price;
}
private:
size_t min_qty;
double discount;
};
15.8
静态类型在编译时已经确定了,它是变量声明时的类型或表达式生成的类型.而动态类型则是变量或表达式表示的内存中的对象的类型.动态类型直到运行时才能知道.
例如:
Quote *pQuote=new Bulk_quote;
指针pQuote的静态类型是Quote,在编译时就已经确定了.但是它的动态类型是Bulk_quote.直到运行时才知道它指向的是基类还是派生类.如果一个变量非指针也能引用.则它的静态类型和动态类型永远一致.但基类的指针或引用可能与其动态类型不一致.
15.9
Bulk_quote bulk;
Quote* pQuote = &bulk;
Quote& rQuote = bulk;
//传递给item的如果是派生类对象,即是静态类型和动态类型不同的情况.
double print_total(ostream & os, const Quote & item, size_t n);
15.10
在要求使用基类对象的地方,可以使用派生类型的对象来代替,是静态类型和动态类型不同的经典例子.
15.11
virtual void debug() { //题目要加的东西
cout << "bookNo=" << bookNo << " price=" << price << endl;
}
virtual void debug() {
Quote::debug(); //bookNo变量为private,所以不能直接访问bookNo
//只能调用基类的debug()函数来显示
cout << "min_qty=" << min_qty << "discount=" << discount << endl;
}
#include<iostream>
#include<string>
#include<vector>
#include <algorithm>
#include <functional>
#include<map>
using namespace std;
class Quote {
public:
Quote() = default;
Quote(const string& book, double sales_price) : bookNo(book), price(sales_price) {}
string isbn() const { return bookNo; }
//返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual double net_price(size_t n)const { return n * price; }
virtual ~Quote() = default;
virtual void debug() { //题目要加的东西
cout << "bookNo=" << bookNo << " price=" << price << endl;
}
private:
string bookNo; //书籍的ISBN编号
protected:
double price = 0.0; //代表普通状态下不打折的价格
};
double print_total(ostream& os, const Quote& item, size_t n) {
//根据传入item形参的对象类型调用Quote::net_price
//或者Bulk_quote::net_price
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold:" << n << " total due:" << ret << endl;
return ret;
}
class Bulk_quote :public Quote {
public:
double net_price(size_t cnt) const override {
if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
virtual void debug() {
Quote::debug(); //bookNo变量为private,所以不能直接访问bookNo
//只能调用基类的debug()函数来显示
cout << "min_qty=" << min_qty << "discount=" << discount << endl;
}
private:
size_t min_qty;
double discount;
};
class Limited_quote :public Quote {
public:
double net_price(size_t cnt) const override {
if (cnt <= min_qty) return cnt * (1 - discount) * price;
else return min_qty * (1 - discount) * price + (cnt - min_qty) * price;
}
private:
size_t min_qty;
double discount;
};
int main(void) {
Bulk_quote bulk;
Quote* pQuote = &bulk;
Quote& rQuote = bulk;
//传递给item的如果是派生类对象,即是静态类型和动态类型不同的情况.
double print_total(ostream & os, const Quote & item, size_t n);
return 0;
}
15.12
override:在C++11新标准中我们可以使用override关键字来说明派生类中的虚函数,这么做的好处是在使得我们的意图更加清晰即明确地告诉编译器我们想要覆盖掉已存在的虚函数.如果定义了一个函数与基类中的名字相同但是形参列表不同.在不使用override关键字的时候这种函数定义是合法的.在使用了override关键字之后这种行为是非法的.编译器会提示出错.
final.如果我们将某个函数定义成final.则不允许后续的派生类来覆盖这个函数,否则会报错.
15.13
没有声明类derived是从base派生过来的
struct base {
base(string szNm) :basename(szNm) {}
string name() {
return basename;
}
virtual void print(ostream& os) {
os << basename;
}
private:
string basename;
};
struct derived :public base {
derived(string szName, int iVal) :base(szName), mem(iVal) {}
void print(ostream &os) override{
base::print(os);
os << "--" << mem;
}
private:
int mem;
};
int main(void) {
string a = "Link";
base T(a);
ostream& os=cout;
//T.print(cout);
derived Test(a,9);
Test.print(os);
return 0;
}
15.14
(a) base
(b) de
© b
(d) b
(e) b
(f) de
15.15
class Disc_quote :public Quote {
public :
Disc_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), quantity(qty), discount(disc) {}
double net_price(size_t cnt) const = 0;
protected:
size_t quantity;
double discount;
};
class Bulk_quote :public Disc_quote {
public:
Bulk_quote(const string& book = "", double sales_price = 0, size_t qty = 0, double disc_rate = 0) :
Disc_quote(book, sales_price, qty, disc_rate) {}
double net_price(size_t cnt)const {
if (cnt > quantity) return cnt * (1 - discount) * price;
else return cnt * price;
}
};
15.16
class Limited_quote :public Disc_quote {
public:
Limited_quote(const string& book = "", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0) :
Disc_quote(book, sales_price, qty, disc_rate) {}
double net_price(size_t cnt) const override {
if (cnt <= quantity)
return cnt * (1 - discount) * price;
else
return quantity * (1 - discount) * price + (cnt - quantity) * price;
}
private:
size_t min_qty;
double discount;
};
15.17
Severity Code Description Project File Line Suppression State
Error (active) E0322 object of abstract class type “Disc_quote” is not allowed: C++Primer E:\File\VS\C++Primer\Source.cpp 101
这个是我的编译器的错误.
15.18
只有d1和dd1类可以
因为只有它们是公有的继承类.
15.19
Derived_from_Private:private Priv_Derv这个类的函数不合法
1 无论派生类以什么方式继承基类,派生类的成员函数和友元都能使用派生类向基类的转换.派生类向其直接基类的类型转换对于派生类的成员和函数来说永远是可访问的
2 如果派生类继承基类的方式是公有的或者受保护的.则派生类的成员和友元可以使用派生类的类型转换.反之,如果派生类继承基类的方式是私有的.则不能使用.
15.20
-----------------占位符----------------
15.21
对b中的几何图元组织成了一个继承层次:
1 公共基类 Figure,表示几何图元:
2 类Rectangle,Circle,Sphere和Cone 分别表示 矩形,圆,球形,锥形
定义为Figure的派生类.
15.22
class Figure {
public:
Figure(double, double);
protected:
double xSize, ySize;
};
class Figure_2D :public Figure {
public:
Figure_2D(double, double);
virtual double area() = 0; //求面积操作:纯虚函数
virtual double pcrimeter() = 0; //求周长操作:纯虚函数
};
class Figure_3D :public Figure {
public:
Figure_3D(double, double, double);
virtual double cubage() = 0;
protected:
double zSize;
};
class Rectangle :public Figure_2D {
public:
Rectangle(double, double);
virtual double area();
virtual double perimeter();
};
class Circle :public Figure_2D {
public:
Circle(double, double);
virtual double area();
virtual double perimeter();
};
class Sphere :public Figure_3D {
public:
Sphere(double, double, double);
virtual double cubage();
};
class Cone :public Figure_3D {
public:
Cone(double, double, double);
virtual double cubage();
};
15.23
1 将D1类的fcn函数更改为int fcn()
2 p2->fcn(42) 这一条调用语句将会出错.
15.24
作为基类使用的类应该具有虚析构函数,以保证在删除指向动态分配对象的基类指针时,根据指针实际指向的对象所属的类型运行适当的析构函数.
虚析构函数可以为空.即不执行任何操作.一般而言,析构函数的主要作用是清楚本类中定义的数据成员.如果该类没有定义指针类
15.25
因为Disc_quote的默认构造函数会运行Quote的默认构造函数,而Quote默认构造函数会完成成员的初始化工作
如果去掉该构造函数的话.Bulk_quote的默认构造函数而无法完成Disc_quote的初始化工作.
15.26
#include<iostream>
#include<string>
#include<vector>
#include <algorithm>
#include <functional>
#include<map>
using namespace std;
class Quote {
public:
Quote() = default;
Quote(const string& book=" ", double sales_price=0.0) : bookNo(book), price(sales_price) {
cout << "Quote constructor is running " << endl;
}
string isbn() const { return bookNo; }
//返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual double net_price(size_t n)const { return n * price; }
virtual ~Quote() {
cout << "Quote destructor is running " << endl;
}
virtual void debug() { //题目要加的东西
cout << "bookNo=" << bookNo << " price=" << price << endl;
}
friend ostream& operator <<(ostream&, Quote&);
private:
string bookNo; //书籍的ISBN编号
protected:
double price = 0.0; //代表普通状态下不打折的价格
};
ostream& operator<<(ostream& os, Quote &e) {
os << "\tUsing operato << (ostream&, Quote&);" << endl;
return os;
}
double print_total(ostream& os, const Quote& item, size_t n) {
//根据传入item形参的对象类型调用Quote::net_price
//或者Bulk_quote::net_price
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold:" << n << " total due:" << ret << endl;
return ret;
}
class Bulk_quote :public Quote {
public:
Bulk_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), min_qty(qty), discount(disc) {
cout << "Bulk_constructor is running " << endl;
}
double net_price(size_t cnt) const override {
if (cnt > min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
virtual void debug() override{
Quote::debug(); //bookNo变量为private,所以不能直接访问bookNo
//只能调用基类的debug()函数来显示
cout << "min_qty=" << min_qty << "discount=" << discount << endl;
}
~Bulk_quote() {
cout << "Bulk_quote destructor is running " << endl;
}
private:
size_t min_qty;
double discount;
};
ostream& operator <<(ostream& os, Bulk_quote& bq) {
os << "\tUsing operator<<(ostream &,Bulk_quote&)" << endl;
return os;
}
//class Limited_quote :public Disc_quote {
//public:
// Limited_quote(const string& book = "", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0) :
// Disc_quote(book, sales_price, qty, disc_rate) {}
// double net_price(size_t cnt) const override {
// if (cnt <= quantity)
// return cnt * (1 - discount) * price;
// else
// return quantity * (1 - discount) * price + (cnt - quantity) * price;
// }
//private:
// size_t min_qty;
// double discount;
//};
struct base {
base(string szNm) :basename(szNm) {}
string name() {
return basename;
}
virtual void print(ostream& os) {
os << basename;
}
private:
string basename;
};
struct derived :public base {
derived(string szName, int iVal) :base(szName), mem(iVal) {}
void print(ostream &os) override{
base::print(os);
os << "--" << mem;
}
private:
int mem;
};
class Disc_quote :public Quote {
public :
Disc_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), quantity(qty), discount(disc) {}
double net_price(size_t cnt) const = 0;
protected:
size_t quantity;
double discount;
};
//class Bulk_quote :public Disc_quote {
//public:
// Bulk_quote(const string& book = "", double sales_price = 0, size_t qty = 0, double disc_rate = 0) :
// Disc_quote(book, sales_price, qty, disc_rate) {}
// double net_price(size_t cnt)const {
// if (cnt > quantity) return cnt * (1 - discount) * price;
// else return cnt * price;
// }
//};
class Figure {
public:
Figure(double, double);
protected:
double xSize, ySize;
};
class Figure_2D :public Figure {
public:
Figure_2D(double, double);
virtual double area() = 0; //求面积操作:纯虚函数
virtual double pcrimeter() = 0; //求周长操作:纯虚函数
};
class Figure_3D :public Figure {
public:
Figure_3D(double, double, double);
virtual double cubage() = 0;
protected:
double zSize;
};
class Rectangle :public Figure_2D {
public:
Rectangle(double, double);
virtual double area();
virtual double perimeter();
};
class Circle :public Figure_2D {
public:
Circle(double, double);
virtual double area();
virtual double perimeter();
};
class Sphere :public Figure_3D {
public:
Sphere(double, double, double);
virtual double cubage();
};
class Cone :public Figure_3D {
public:
Cone(double, double, double);
virtual double cubage();
};
int main(void) {
Quote base("C++ Primer", 128.0);
Bulk_quote bulk("Core Python Programming", 89, 5, 0.19);
cout << base << endl;
cout << bulk << endl;
return 0;
}
输入和输出
Quote constructor is running
Quote constructor is running
Bulk_constructor is running
Using operato << (ostream&, Quote&);
Using operator<<(ostream &,Bulk_quote&)
Bulk_quote destructor is running
Quote destructor is running
Quote destructor is running
15.27
class Disc_quote :public Quote {
public :
Disc_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), quantity(qty), discount(disc) {}
double net_price(size_t cnt) const = 0;
protected:
size_t quantity;
double discount;
};
class Bulk_quote :public Disc_quote {
public:
/*Bulk_quote(const string& book = "", double sales_price = 0, size_t qty = 0, double disc_rate = 0) :
Disc_quote(book, sales_price, qty, disc_rate) {}*/
using Disc_quote::Disc_quote;
double net_price(size_t cnt)const {
if (cnt > quantity) return cnt * (1 - discount) * price;
else return cnt * price;
}
};
15.28
#include<iostream>
#include<string>
#include<vector>
#include <algorithm>
#include <functional>
#include<map>
using namespace std;
class Quote {
public:
Quote() = default;
Quote(const string& book=" ", double sales_price=0.0) : bookNo(book), price(sales_price) {
//cout << "Quote constructor is running " << endl;
}
string isbn() const { return bookNo; }
//返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
virtual double net_price(size_t n)const { return n * price; }
virtual ~Quote() {
//cout << "Quote destructor is running " << endl;
}
virtual void debug() { //题目要加的东西
//cout << "bookNo=" << bookNo << " price=" << price << endl;
}
//friend ostream& operator <<(ostream&, Quote&);
private:
string bookNo; //书籍的ISBN编号
protected:
double price = 0.0; //代表普通状态下不打折的价格
};
ostream& operator<<(ostream& os, Quote &e) {
//os << "\tUsing operato << (ostream&, Quote&);" << endl;
return os;
}
double print_total(ostream& os, const Quote& item, size_t n) {
//根据传入item形参的对象类型调用Quote::net_price
//或者Bulk_quote::net_price
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold:" << n << " total due:" << ret << endl;
return ret;
}
class Bulk_quote :public Quote {
public:
Bulk_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), min_qty(qty), discount(disc) {
//cout << "Bulk_constructor is running " << endl;
}
double net_price(size_t cnt) const override {
if (cnt > min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
virtual void debug() override{
Quote::debug(); //bookNo变量为private,所以不能直接访问bookNo
//只能调用基类的debug()函数来显示
//cout << "min_qty=" << min_qty << "discount=" << discount << endl;
}
~Bulk_quote() {
//cout << "Bulk_quote destructor is running " << endl;
}
private:
size_t min_qty;
double discount;
};
ostream& operator <<(ostream& os, Bulk_quote& bq) {
os << "\tUsing operator<<(ostream &,Bulk_quote&)" << endl;
return os;
}
//class Limited_quote :public Disc_quote {
//public:
// Limited_quote(const string& book = "", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0) :
// Disc_quote(book, sales_price, qty, disc_rate) {}
// double net_price(size_t cnt) const override {
// if (cnt <= quantity)
// return cnt * (1 - discount) * price;
// else
// return quantity * (1 - discount) * price + (cnt - quantity) * price;
// }
//private:
// size_t min_qty;
// double discount;
//};
//struct base {
// base(string szNm) :basename(szNm) {}
// string name() {
// return basename;
// }
// virtual void print(ostream& os) {
// os << basename;
// }
//private:
// string basename;
//};
//struct derived :public base {
// derived(string szName, int iVal) :base(szName), mem(iVal) {}
// void print(ostream &os) override{
// base::print(os);
// os << "--" << mem;
// }
//private:
// int mem;
//};
class Disc_quote :public Quote {
public :
Disc_quote(const string& book = " ", double sales_price = 0.0, size_t qty = 0, double disc = 0.0) :
Quote(book, sales_price), quantity(qty), discount(disc) {}
double net_price(size_t cnt) const = 0;
protected:
size_t quantity;
double discount;
};
//class Bulk_quote :public Disc_quote {
//public:
// /*Bulk_quote(const string& book = "", double sales_price = 0, size_t qty = 0, double disc_rate = 0) :
// Disc_quote(book, sales_price, qty, disc_rate) {}*/
// using Disc_quote::Disc_quote;
// double net_price(size_t cnt)const {
// if (cnt > quantity) return cnt * (1 - discount) * price;
// else return cnt * price;
// }
//};
//class Figure {
//public:
// Figure(double, double);
//protected:
// double xSize, ySize;
//};
//class Figure_2D :public Figure {
//public:
// Figure_2D(double, double);
// virtual double area() = 0; //求面积操作:纯虚函数
// virtual double pcrimeter() = 0; //求周长操作:纯虚函数
//};
//class Figure_3D :public Figure {
//public:
// Figure_3D(double, double, double);
// virtual double cubage() = 0;
//protected:
// double zSize;
//};
//class Rectangle :public Figure_2D {
//public:
// Rectangle(double, double);
// virtual double area();
// virtual double perimeter();
//};
//class Circle :public Figure_2D {
//public:
// Circle(double, double);
// virtual double area();
// virtual double perimeter();
//};
//class Sphere :public Figure_3D {
//public:
// Sphere(double, double, double);
// virtual double cubage();
//};
//class Cone :public Figure_3D {
//public:
// Cone(double, double, double);
// virtual double cubage();
//};
int main(void) {
vector<Quote> T;
for (size_t i = 0; i != 10; ++i) {
Bulk_quote item("C++ Primer", 6.5, 0.5);
T.push_back(item);
}
double sum = 0;
for (auto i : T) {
sum += i.net_price(10);
}
cout << sum << endl;
return 0;
}
15.29
改
vector<shared_ptr<Quote>> T;
15.30
class Basket {
public:
//Basket使用合成的默认构造函数和拷贝控制成员
void add_item(const shared_ptr<Quote>& sale) { items.insert(sale); }
private:
//该函数用于比较shared_ptr,multiset成员会用到它
static bool compare(const shared_ptr<Quote>& lhs, const shared_ptr<Quote>& rhs) {
return lhs->isbn() < rhs->isbn();
}
//multiset保存多个报价,按照compare成员排序
multiset<shared_ptr<Quote>, decltype(compare)*>items{compare};
double total_receipt(ostream& os) const;
};
double Basket::total_receipt(ostream& os) const {
double sum = 0.0; //保存实时计算出的总价格.
//iter指向ISBN相同的一批元素中的第一个
//upper_bound返回一个迭代器,该迭代器指向这批元素中的最后一个的下一个位置
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 << endl;
return sum;
}
15.31
(a) 创建12个对象,6个Query_base
3个WordQuery
1 个NotQuery
1个AndQuery
1个OrQuery
(b) 与(a)同
© 共创建14个对象,7个Query_base对象及其相关联的句柄,7个Query_base对象分别是4个WordQuery对象 2个AndQuery对象1个OrQuery对象.
15.32
Query类未定义自己的拷贝/移动控制成员,当进行这些操作时,执行默认语义,而其唯一的数据成员是Query_base的shared_ptr.因此,当拷贝,移动,赋值或销毁其唯一的数据成员 Query_base的shared_ptr时,会调用shared_ptr的对应控制成员.从而实现多个Query对象正确共享一个Query_base.而shared_ptr的控制成员调用Query_base的控制成员时,由于指向的可能是Query_base的派生类对象.因此可能在类层次中进行相应的拷贝/移动操作,调用Query_base的派生类的相应控制成员.
15.33
Query_base是一个虚基类,不允许直接声明其对象.
当其派生类对象进行这些操作时,会调用Query_base的相应控制成员.而Query_base没有定义自己的拷贝/移动控制成员.实际上没有任何数据成员.无序定义这些操作,因此进行这些操作时,执行默认定义,什么也不会发生.
15.34
15.35
15.36
在各个类的构造函数和rep中添加打印语句即可,注意,Query类有一个public,和一个private共两个构造函数
15.37
书中的实现方式是用Query类封装了Query_base指针.管理实际查询处理用到的不同Query类型对象.
如果不适用Query类.则涉及使用Query类型的地方.都要改成Query_base指针.如创建单个词查询时,就必须创建WordQuery类而不是Query对象.几个重载的布尔类型运算符也不能再针对Query对象.而需针对Query_base指针.从而复杂的查询请求无法携程目前的简单形式.需要逐个运算完成.将结果赋予Query_base指针.
15.38
第一条声明不合法,BinaryQuery是纯虚函数
第二条声明不合法,不能将Query转换为AndQuery
第三条声明不合法,不能将Query转换为OrQuery
15.39
略
15.40
OrQuery的eval从lhs到rhs获取范围来构造set(或向其插入),而set的构造和插入操作可以正确处理空范围.因此无论lhs和rhs的结果是否为空集.eval都能得到正确结果.