C++ Primer课后习题解答(第十五章)
Exercises Section 15.2.1
Ex15.1
一个类的 virtual 成员可以被其派生类重写
Ex15.2
被 protected 修饰的类成员可以被该类的派生类访问,而被 private 修饰的类成员则不行。
Ex15.3
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(ostream &os, const Quote &item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
return ret;
}
Exercises Section 15.2.2
Ex15.4
class Base { ... };
a) class Derived : public Derived() { ... }; // 错误;一个类不能是自己的派生类
b) class Derived : private Base { ... }; // 正确
c) class Derived : public Base; // 错误;声明列表必须完整或者不出现声明列表
Ex15.5
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const std::string &book, double p, std::size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { }
double net_price(std::size_t) const override;
private:
std::size_t min_qty = 0;
double discount = 0.0;
};
double Bulk_quote::net_price(size_t cnt) const
{
if (cnt >= min_qty)
return cnt * (1 - discount) * price;
else
return cnt * price;
}
Ex15.6
#include<iostream>
using namespace std;
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;
};
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const std::string &book, double p, std::size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { }
double net_price(std::size_t) const override;
private:
std::size_t min_qty = 0;
double discount = 0.0;
};
double print_total(ostream &os, const Quote &item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
return ret;
}
double Bulk_quote::net_price(size_t cnt) const
{
if (cnt >= min_qty)
return cnt * (1 - discount) * price;
else
return cnt * price;
}
int main()
{
Quote q("199-9-X", 20);
Bulk_quote bq("199-9-X", 20, 10, 0.2);
print_total(cout, q, 10);
print_total(cout, bq, 10);
system("pause");
return 0;
}
Ex15.7
class Limit_Quote : public Quote
{
public:
Limit_Quote() = default;
Limit_Quote(const std::string &book, double p, std::size_t cnt, double disc):
Quote(book, p), count(cnt), discount(disc) { }
double net_price(std::size_t sz) const override;
private:
std::size_t count = 0;
double discount = 0;
};
double Limit_Quote::net_price(size_t sz) const
{
if (count >= sz)
return sz * (1 - discount) * price;
else
return sz * price;
}
Exercises Section 15.2.3
Ex15.8
静态类型:在编译时刻就知道的类型;变量声明类型或者表达式产生的类型。
动态类型:只在运行时刻才知道的类型;内存中变量或者表达式表示的对象类型。
Ex15.9
- 当对象的静态类型和对象的动态类型之间存在隐式转换
- 当基类指针或引用指向派生类对象
- 当虚函数通过指针或引用被调用
Ex15.10
ifstream 类传递了一个派生类对象给 read 函数。
Exercises Section 15.3
Ex15.11
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 void debug(ostream &os) { os << "BookNO: " << bookNo << " price: " << price << endl; }
virtual ~Quote() = default;
private:
std::string bookNo;
protected:
double price = 0.0;
};
Ex15.12
override:如果在派生类中用 override 标记了某函数,而基类中没有对应的该函数,则发生错误。
final:基类中某函数定义为 final,那么派生类中对其重写则发生错误。
Ex15.13
class base
{
public:
string name() { return basename; }
virtual void print(ostream &os) { os << basename; }
private:
string basename;
};
class derived : public base
{
public:
// 如果派生虚函数想要调用基类版本但是省略了范围操作符,则会调用派生版本自身,产生无限递归
void print(ostream &os) { print(os); os << " " << i; }
private:
int i;
};
修改后如下:
class base
{
public:
string name() { return basename; }
virtual void print(ostream &os) { os << basename; }
private:
string basename;
};
class derived : public base
{
public:
void print(ostream &os) { base::print(os); os << " " << i; }
private:
int i;
};
Ex15.14
base bobj; base *bp1 = &bobj; base &br1 = bobj;
derived dobj; base *bp2 = &dobj; base &br2 = dobj;
a) bobj.print(); // 在编译时刻被调用
b) dobj.print(); // 在运行时刻被调用
c) bp1->name(); // 在编译时刻被调用
d) bp2->name(); // 在编译时刻被调用
e) br1.print(); // 在编译时刻被调用
f) br2.print(); // 在运行时刻被调用
Exercises Section 15.4
Ex15.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 price, std::size_t qty, double disc):
Disc_quote(book, price, qty, disc) { }
double net_price(std::size_t) const override;
};
Ex15.16
class Limit_quote : public Disc_quote
{
public:
Limit_quote() = default;
Limit_quote(const std::string &book, double price, std::size_t qty, double disc):
Disc_quote(book, price, qty, disc) { }
double net_price(std::size_t) const override;
};
double Limit_quote::net_price(size_t sz)
{
if (quantity >= sz)
return sz * (1 - discount) * price;
else
return sz * price;
}
Ex15.17
Exercises Section 15.5
Ex15.18
Base *p = &d1; // d1 has type Pub_Derv
p = &d2; // d2 has type Priv_Derv
p = &d3; // d3 has type Prot_Derv
p = &dd1; // dd1 has type Derived_from_Public
p = &dd2; // dd2 has type Derived_from_Private
p = &dd3; // dd3 has type Derived_from_Protected
d1 和 dd1 能够合法赋值,只有派生类继承基类为 public 时,用户才能进行派生类到基类的转换。
Ex15.19
Derived_from_Private 不合法;
当D继承自B:对于用户代码,只有 public 继承,能使用D到B的转换;
对于D的成员和友元,任何继承方式都能使用D到B的转换;
对于D的派生类的成员和友元,public 和 protected 继承能使用D到B的转换。
Ex15.20
// 注释掉的代码非法
#include <iostream>
using namespace std;
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;
cout << "Pub_Derv" << endl;
}
};
struct Priv_Derv: private Base
{
int f1() const { return prot_mem; }
void memfcn(Base &b)
{
b = *this;
cout << "Priv_Derv" << endl;
}
};
struct Prot_Derv: protected Base
{
int f2() { return prot_mem; }
void memfcn(Base &b)
{
b = *this;
cout << "Prot_Derv" << endl;
}
};
struct Derived_from_Public: public Pub_Derv
{
int use_base() { return prot_mem; }
void memfcn(Base &b)
{
b = *this;
cout << "Derived_from_Public" << endl;
}
};
/*
struct Derived_from_Private: public Priv_Derv
{
int use_base() { return prot_mem; }
void memfcn(Base &b)
{
b = *this;
cout << "Derived_from_Private" << endl;
}
};
*/
struct Derived_from_Protected: protected Prot_Derv
{
int use_base() { return prot_mem; }
void memfcn(Base &b)
{
b = *this;
cout << "Derived_from_Protected" << endl;
}
};
int main()
{
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public dd1;
// Derived_from_Private dd2;
Derived_from_Protected dd3;
//用户代码
Base base;
Base *p = &d1;
// p = &d2;
// p = &d3;
p = &dd1;
// p = &dd2;
// p = &dd3;
//成员调用
d1.memfcn(base);
d2.memfcn(base);
d3.memfcn(base);
//派生类的成员调用
dd1.memfcn(base);
// dd2.memfcn(base);
dd3.memfcn(base);
system("pause");
return 0;
}
Ex 15.21
(b)的继承体系:公共基类 Figure,派生类 Figure_2D 和 Figure_3D 继承自 Figure,Retangle 和 Circle 继承自 Figure_2D,Sphere 和 Cone 继承自Figure_3D。
Ex15.22
class Figure
{
public:
Figure() = default;
Figure(double, double);
private:
double x, y;
};
class Figure_2D : public Figure
{
public:
Figure_2D() = default;
Figure_2D(double, double);
virtual double area() = 0;
virtual double perimeter() = 0;
};
class Figure_3D : public Figure
{
public:
Figure_3D() = default;
Figure_3D(double, double, double);
virtual double cubage() = 0;
protected:
double z;
};
class Retangle : public Figure_2D
{
public:
Retangle() = default;
Retangle(double, double);
double area() override;
double perimeter() override;
};
class Circle : public Figure_2D
{
public:
Circle() = default;
Circle(double, double);
double area() override;
double perimeter() override;
};
class Sphere : public Figure_3D
{
public:
Sphere() = default;
Sphere(double, double, double);
double cubage() override;
};
class Cone : public Figure_3D
{
public:
Cone() = default;
Cone(double, double, double);
double cubage() override;
};
Exercises Section 15.6
Ex15.23
class Base
{
public:
virtual int fcn();
};
class D1 : public Base
{
public:
int fcn();
virtual void f2();
};
class D2 : public D1
{
public:
int fcn(int);
int fcn();
void f2();
};
调用语句解析:
Base bobj; D1 d1obj; D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = d2obj;
bp1->fcn(); // 调用Base::fcn
bp2->fcn(); // 调用D1::fcn
bp3->fcn(); // 调用D2::fcn
D1 *d1p = &d1obj; D2 *d2p = &d2obj;
bp2->f2(); // 错误,Base没有f2()
d1p->f2(); // 调用D1::f2()
d2p->f2(); // 调用D2::f2()
Base *p1 = &d2obj; D1 *p2 = &d2obj; D2 *p3 = &d2obj;
p1->fcn(42); // 错误,Base没有fcn(int)
p2->fcn(42); // 错误,D1没有fcn(int)
p3->fcn(42); // 静态绑定,调用D2::fcn(int)
Exercises Section 15.7.1
Ex15.24
基类需要被 virtual 修饰的析构函数,在静态类型和动态类型不同时,保证运行正确的析构函数。
虚析构函数必须清除该类中的成员数据,可以定义为 = default 版本。
Exercises Section 15.7.2
Ex15.25
Disc_quote 的默认构造函数会调用 Quote 的默认构造函数,完成基类部分的成员初始化工作;如果去掉该默认构造函数,Bulk_quote 的默认构造函数将无法完成其基类部分的初始化工作。
Exercises Section 15.7.3
Ex15.26
#include<iostream>
using namespace std;
class Quote
{
public:
Quote() = default;
Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { cout << "Quote constructor" << endl; }
Quote(Quote &q): bookNo(q.bookNo), price(q.price) { cout << "Quote copy constructor" << endl; }
Quote(Quote &&q):bookNo(std::move(q.bookNo)), price(std::move(q.price)) { cout << "Quote move constructor" << endl; }
Quote & operator=(const Quote &q)
{
bookNo = q.bookNo;
price = q.price;
cout << "Quote operator=" << endl;
return *this;
}
Quote & operator=(Quote &&q)
{
bookNo = std::move(q.bookNo);
price = std::move(q.price);
cout << "Quote operator move = " << endl;
return *this;
}
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const
{
return n * price;
}
virtual void debug() { cout << "bookNo: " << bookNo << " price: " << price << endl; }
virtual ~Quote() { cout << "Quote destructor" << endl; }
private:
string bookNo;
protected:
double price = 0.0;
};
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string &book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { cout << "Bulk_quote constructor" << endl; }
Bulk_quote(Bulk_quote &bq): Quote(bq), min_qty(bq.min_qty), discount(bq.discount) { cout << "Bulk_quote copy constructor" << endl; }
Bulk_quote(Bulk_quote &&bq): Quote(std::move(bq)), min_qty(std::move(bq.min_qty)), discount(std::move(bq.discount))
{ cout << "Bulk_quote move constructor" << endl; }
Bulk_quote & operator=(const Bulk_quote &bq)
{
Quote::operator=(bq);
min_qty = bq.min_qty;
discount = bq.discount;
cout << "Bulk_quote operator= constructor" << endl;
return *this;
}
Bulk_quote & operator=(const Bulk_quote &&bq)
{
Quote::operator=(std::move(bq));
min_qty = std::move(bq.min_qty);
discount = std::move(bq.discount);
cout << "Bulk_quote operator move = constructor" << endl;
return *this;
}
double net_price(size_t) const override;
void debug() override;
~Bulk_quote() { cout << "Bulk_quote destrucotr" << endl; }
private:
size_t min_qty = 0;
double discount = 0.0;
};
double Bulk_quote::net_price(size_t sz) const
{
if (sz >= min_qty)
return sz * (1 - discount) * price;
else
return sz * price;
}
void Bulk_quote::debug()
{
Quote::debug();
cout << " min_qty: " << min_qty << " discount: " << discount << endl;
}
int main()
{
Quote q("199-9-X", 10.0);
Bulk_quote bq("199-5-X", 15.0, 20, 0.2);
Quote q1(q);
Bulk_quote bq2(bq);
q1 = q;
bq2 = bq;
q1 = std::move(q);
bq2 = std::move(bq);
system("pause");
return 0;
}
Exercises Section 15.7.4
Ex15.27
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
using Quote::Quote;
Bulk_quote(Bulk_quote &bq): Quote(bq), min_qty(bq.min_qty), discount(bq.discount) { }
Bulk_quote(Bulk_quote &&bq): Quote(std::move(bq)), min_qty(std::move(bq.min_qty)), discount(std::move(bq.discount)) { }
Bulk_quote & operator=(const Bulk_quote &bq)
{
Quote::operator=(bq);
min_qty = bq.min_qty;
discount = bq.discount;
return *this;
}
Bulk_quote & operator=(const Bulk_quote &&bq)
{
Quote::operator=(std::move(bq));
min_qty = std::move(bq.min_qty);
discount = std::move(bq.discount);
return *this;
}
double net_price(size_t) const override;
void debug() override;
~Bulk_quote();
private:
size_t min_qty = 0;
double discount = 0.0;
};
Exercises Section 15.8
Ex15.28
#include<iostream>
#include<vector>
using namespace std;
class Quote
{
public:
Quote() = default;
Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { }
Quote(Quote &q): bookNo(q.bookNo), price(q.price) { }
Quote(Quote &&q):bookNo(std::move(q.bookNo)), price(std::move(q.price)) { }
Quote & operator=(const Quote &q)
{
bookNo = q.bookNo;
price = q.price;
return *this;
}
Quote & operator=(Quote &&q)
{
bookNo = std::move(q.bookNo);
price = std::move(q.price);
return *this;
}
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const
{
return n * price;
}
virtual void debug() { }
virtual ~Quote() { }
private:
string bookNo;
protected:
double price = 0.0;
};
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string &book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { }
Bulk_quote(Bulk_quote &bq): Quote(bq), min_qty(bq.min_qty), discount(bq.discount) { }
Bulk_quote(Bulk_quote &&bq): Quote(std::move(bq)), min_qty(std::move(bq.min_qty)), discount(std::move(bq.discount)) { }
Bulk_quote & operator=(const Bulk_quote &bq)
{
Quote::operator=(bq);
min_qty = bq.min_qty;
discount = bq.discount;
return *this;
}
Bulk_quote & operator=(const Bulk_quote &&bq)
{
Quote::operator=(std::move(bq));
min_qty = std::move(bq.min_qty);
discount = std::move(bq.discount);
return *this;
}
double net_price(size_t) const override;
void debug() override;
~Bulk_quote() { }
private:
size_t min_qty = 0;
double discount = 0.0;
};
double Bulk_quote::net_price(size_t sz) const
{
if (sz >= min_qty)
return sz * (1 - discount) * price;
else
return sz * price;
}
void Bulk_quote::debug()
{
Quote::debug();
cout << " min_qty: " << min_qty << " discount: " << discount << endl;
}
int main()
{
vector<Quote> basket;
basket.push_back(Bulk_quote("199-9-X", 50.0, 10, 0.2));
double sum = 0.0;
for (auto &v : basket)
sum += v.net_price(20);
cout << sum << endl;
system("pause");
return 0;
}
Ex15.29
#include<iostream>
#include<vector>
#include<memory>
using namespace std;
class Quote
{
public:
Quote() = default;
Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { }
Quote(Quote &q): bookNo(q.bookNo), price(q.price) { }
Quote(Quote &&q):bookNo(std::move(q.bookNo)), price(std::move(q.price)) { }
Quote & operator=(const Quote &q)
{
bookNo = q.bookNo;
price = q.price;
return *this;
}
Quote & operator=(Quote &&q)
{
bookNo = std::move(q.bookNo);
price = std::move(q.price);
return *this;
}
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const
{
return n * price;
}
virtual void debug() { }
virtual ~Quote() { }
private:
string bookNo;
protected:
double price = 0.0;
};
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string &book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { }
Bulk_quote(Bulk_quote &bq): Quote(bq), min_qty(bq.min_qty), discount(bq.discount) { }
Bulk_quote(Bulk_quote &&bq): Quote(std::move(bq)), min_qty(std::move(bq.min_qty)), discount(std::move(bq.discount)) { }
Bulk_quote & operator=(const Bulk_quote &bq)
{
Quote::operator=(bq);
min_qty = bq.min_qty;
discount = bq.discount;
return *this;
}
Bulk_quote & operator=(const Bulk_quote &&bq)
{
Quote::operator=(std::move(bq));
min_qty = std::move(bq.min_qty);
discount = std::move(bq.discount);
return *this;
}
double net_price(size_t) const override;
void debug() override;
~Bulk_quote() { }
private:
size_t min_qty = 0;
double discount = 0.0;
};
double Bulk_quote::net_price(size_t sz) const
{
if (sz >= min_qty)
return sz * (1 - discount) * price;
else
return sz * price;
}
void Bulk_quote::debug()
{
Quote::debug();
cout << " min_qty: " << min_qty << " discount: " << discount << endl;
}
int main()
{
vector<shared_ptr<Quote>> basket;
basket.push_back(make_shared<Bulk_quote>("199-9-X", 50.0, 10, 0.2));
double sum = 0.0;
for (auto &v : basket)
sum += v->net_price(20);
cout << sum << endl;
system("pause");
return 0;
}
如果为 vector<Quote>
则使用 Quote 类中的 net_price 函数计算,不管添加的类型是否为 Bulk_quote;
如果为 vector<shared_ptr<Quote>>
则用 Bulk_quote 的 net_price 函数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端