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

  1. 当对象的静态类型和对象的动态类型之间存在隐式转换
  2. 当基类指针或引用指向派生类对象
  3. 当虚函数通过指针或引用被调用

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 函数。

posted @   astralcon  阅读(26)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示