C++ Primer(第五版)|练习题答案与解析(第十五章:面向对象程序设计)
本博客主要记录C++ Primer(第五版)中的练习题答案与解析。
参考:C++ Primer
C++ Primer
C++Primer
练习题15.1
什么是虚成员?
P526-52。.虚成员是基类希望派生类进行覆盖的函数,在其成员前加关键字virtual,使得该成员可以实现动态绑定。
练习题15.2
protected访问说明符与private有何区别?
P529。
- private成员:即使是基类的派生类也无法直接访问。
- protected成员:基类的派生类可以访问,但禁止其它用户访问。
练习题15.3
定义你自己的Quote类和print_total函数
quote.h
#include <string>
class Quote
{
public:
Quote() = default;
Quote(const std::string &b, double p) :
bookNo(b), price(p) {
}
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;
};
main.c
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include "quote.h"
double print_total (std::ostream& os, const Quote& item, size_t n);
int main()
{
return 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
定义你自己的Bulk_quote类。
bulk_quote.h
#include <quote.h>
class Bulk_quote : public Quote
{
public:
Bulk_quote() = default;
Bulk_quote(const std::string& b, double p, std::size_t q, double disc) :
Quote(b, p), min_qty(q), discount(disc) {
}
double net_price(std::size_t n) const override;
private:
std::size_t min_qty = 0;
double discount = 0.0;
};
bulk_quote.cpp
#include "bulk_quote.h"
double Bulk_quote::net_price(std::size_t n) const
{
return n * price * ( n >= min_qty ? 1 - discount : 1);
}
练习题15.6
将Quote和Bulk_quote的对象传给15.2.1节练习中的print_total函数,检查该函数是否正确。
使用15.3和15.6中定义的类:
main.cpp
#include <iostream>
#include <string>
#include "quote.h"
#include "bulk_quote.h"
double print_total (std::ostream& os, const Quote& item, size_t n);
int main()
{
// ex15.6
Quote q("MLBook", 10.50);
Bulk_quote bq("MLBook", 10.50, 10, 0.3);//超过10本有折扣
print_total(std::cout, q, 10);
print_total(std::cout, bq, 8);//没有折扣
print_total(std::cout, bq, 10);//有折扣
return 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;
}
测试:
ISBN:MLBook# sold: 10 total due: 105
ISBN:MLBook# sold: 8 total due: 84
ISBN:MLBook# sold: 10 total due: 73.5
练习题15.7
定义一个类使其实现一种数量首先的折扣策略,具体策略是:当购买书籍的数量不超过一个给定的限量时享受折扣,如果购买量一旦超过了限量,则超出的部分将以原价销售。
新添:
limit_quote.h
#include "quote.h"
class Limit_quote : public Quote
{
public:
Limit_quote();
Limit_quote(const std::string& b, double p, std::size_t max, double disc):
Quote(b, p), max_qty(max), discount(disc) {
}
double net_price(std::size_t n) const override;
private:
std::size_t max_qty = 0;
double discount = 0.0;
};
limit_quote.cpp
#include "limit_quote.h"
double Limit_quote::net_price(std::size_t n) const
{
if (n > max_qty)
return max_qty * price * discount + (n - max_qty) * price;
else
return n * discount *price;
}
main.cpp
#include <iostream>
#include <string>
#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
double print_total (std::ostream& os, const Quote& item, size_t n);
int main()
{
Quote q("MLBook", 10);
Bulk_quote bq("MLBook", 10, 10, 0.3);
Limit_quote lq("DLBook", 10, 10 , 0.3);
print_total(std::cout, q, 5);
print_total(std::cout, bq, 5);
print_total(std::cout , lq, 5);
return 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;
}
测试:
ISBN:MLBook# sold: 5 total due: 50
ISBN:MLBook# sold: 5 total due: 50
ISBN:DLBook# sold: 5 total due: 15
练习题15.8
给出静态类型和动态类型的定义。
P534
- 静态类型:表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型。
- 动态类型:变量或表达式表示的内存中的对象的类型,动态类型直到运行时才可知。
练习题15.9
在什么情况下表达式的静态类型可能与动态类型不同?请给出三个静态类型与动态类型不同的例子。
P534
基类的指针或引用的静态类型可能与其动态类型不一致,如果表达式既不是指针也不是引用,则它的动态类型永远与静态类型一致。
如15.03中的函数print_total中,参数item的静态类型是其定义的类型Quote&,但如果我们传递一个Bulk_quote&进去,则它的动态类型是Bulk_quote&,此例中item的静态类型和动态类型不一致。
练习题15.10
回忆我们在8.1节(279页)进行的讨论,解释284页中将ifstream传递给Sales_data的read函数的程序是如何工作的。
read是std::istream下的函数,不过由于ifstream继承自istream,因此也可以使用read函数。
练习题15.11
为你的Quote类体系添加一个名为debug的虚函数,令其分别显示每个类的数据成员。
// Quote类
virtual void debug() const;
void Quote::debug() const
{
cout << "This is Quote class." << endl;
cout << "bookNo = " << bookNo << " price = " << price << endl;
}
// Bulk_quote类
void debug() const override;
void Bulk_quote::debug() const
{
cout << "This is Bulk_quote class." << endl;
cout << " price = " << price << endl;
cout << "min_qty = " << min_qty << " discount = " << discount << endl;
}
// Limit_quote类
void debug() const override;
void Limit_quote::debug() const
{
cout << "This is Limit_quote class." << endl;
cout << " price = " << price << endl;
cout << "max_qty = " << max_qty << " discount = " << discount << endl;
}
练习题15.12
有必要将一个成员函数同时声明成override和final吗?为什么?
可以这么做,override意味着重载父类中的虚函数,final意味着禁止子类重载该虚函数。两个用法并不冲突。
练习题15.13
给定下面的类,解释每个print函数的机理,且中存在问题吗?如果有,你该如何修改它?:
class base {
public:
string name() {
return basename; }
virtual void print (ostream& os) {
os << basename; }
private:
string basename = "home";
};
class derived : public base {
public:
void print(ostream& os) {
print(os); os << " " << i; }
// 这里意为重写base类的print函数,并且在其中调用base的print(os),但是由于没有加::范围限定符,导致
// 其调用的还是derived的print函数,造成无限递归。现象是打印完一行home之后就卡住了。
// 改为:void print(ostream& os) override{ base::print(os); os << " " << i; }
// 加override说明是覆盖基类的虚函数。
private:
int i = 2;
};
练习题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()
P527:当使用基类的引用(或指针)调用一个虚函数时将发生动态绑定。
练习题15.15
定义你自己的Disc_quote和Bulk_quote。
disc_quote.h
#include "quote.h"
class Disc_quote :