ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++ Primer 中文第 5 版练习答案 第 15 章 面向对象程序设计(1~27)

2021-10-13 22:04:40  阅读:227  来源: 互联网

标签:27 15 quote price C++ double Bulk Quote const


C++ Primer 中文版(第 5 版)练习解答合集

自己写的解答,如有错误之处,烦请在评论区指正!


1

对于某些成员,基类希望它的派生类各自定义适合自身的版本(而不是不作改变直接继承),此时基类就将这些成员定义成虚成员。

2

对于 protected,派生类有权访问,但是其他用户无法访问

对于 private,派生类和其他用户都无法访问

3

#pragma once
#include <iostream>
using std::ostream;
using std::endl;
#include <string>
using std::string;

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;
protected:
	double price = 0.0;
};

class Bulk_quote : public Quote {
public:
	double net_price(size_t) const override;
};

double printTotal(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;
}

4

a. 不正确,一个类不能派生自身

b. 正确

c. 不正确,在声明中不能写派生列表,这些细节都要放在类的主体中。

5

#pragma once
#include <iostream>
using std::ostream;
using std::endl;
#include <string>
using std::string;

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;
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) { }
	double net_price(size_t) const override;

private:
	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;
}

double printTotal(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;
}

6

Quote.h 代码见上一题。

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main()
{
    Quote q("Harry Potter", 15.0);
    Bulk_quote bq("C++ Primer", 65.0, 3, 0.5);
    printTotal(cout, q, 5);
    printTotal(cout, bq, 5);
    return 0;
}

运行结果:

ISBN: Harry Potter # sold: 5 total due: 75
ISBN: C++ Primer # sold: 5 total due: 162.5

7

class Limited_bulk_quote : public Quote {
public:
	Limited_bulk_quote() = default;
	Limited_bulk_quote(const string& book, double p, size_t qty, double disc) :
		Quote(book, p), max_qty(qty), discount(disc) { }
	double net_price(size_t) const override;

private:
	size_t max_qty = 0;
	double discount = 0.0;
};

double Limited_bulk_quote::net_price(size_t cnt) const {
	if (cnt <= max_qty)
		return cnt * (1 - discount) * price;
	else
		return cnt * price;
}

8

静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型

而动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才可知

9

#include <iostream>
#include "Quote.h"
using namespace std;

int main()
{
    Bulk_quote derived;
    Limited_bulk_quote anotherDerived;
    Quote* baseP = &derived;
    Quote& baseR = derived;
    Quote& baseR1 = anotherDerived;
    return 0;
}

10

read 函数的第一个参数接受一个 iostream 的引用,实际用了 ifstream 类型来调用,这是派生类向基类的隐式转换(仅对指针或引用类型有效)。因为派生类中包括了基类的成员,所以 iostream 的引用可以指向派生类中基类的这部分。

11

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;

/*=============================================
					Quote
=============================================*/
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() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Bulk_quote
=============================================*/
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) { }
	double net_price(size_t) const override;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	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;
}

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main() {
    Quote base("Harry Potter", 15.0);
    Bulk_quote derived("C++ Primer", 65.0, 3, 0.5);
    base.debug();
    putchar('\n');
    derived.debug();
    putchar('\n');
    derived.Quote::debug();
    return 0;
}

运行结果:

bookNo: Harry Potter
price: 15

min_qty: 3
discount: 0.5

bookNo: C++ Primer
price: 65

12

有必要的时候可以这么做,这两个关键字不冲突:

  • override 关键字声明了该函数是对基类中某个虚函数的重写,有助于编译器发现错误,如果参数列表和基类中虚函数不一致,编译器就会报错,防止编译器误认为这是个重载
  • final 关键字则声明了该函数不允许再被派生类重写

13

有问题,derived 类中的 print 函数体中又调用了 print 函数,本意应该是调用基类中的 print,但是如果不显示地指出作用域,就会调用自身引发无限递归。另一个问题是最好在派生类重写的函数头后面加上 override 防止参数列表写错。

#include <iostream>
#include "Quote.h"
using namespace std;

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) override {
        Base::print(os);
        os << " " << i;
    }
private:
    int i;
};

int main() {
    Derived d;
    d.print(cout);
    return 0;
}

14

a. base::print()

b. derived::print()

c. base::name()

d. base::name()

e. base::print()

f. derived::print()

15

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;

/*=============================================
					Quote
=============================================*/
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() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Disc_quote
=============================================*/
class Disc_quote : public Quote {
public:
	Disc_quote() = default;
	Disc_quote(const string& book, double price, size_t qty, double disc) :
		Quote(book, price), quantity(qty), discount(disc) { }
	
	double net_price(size_t) const = 0;

protected:
	size_t quantity = 0;
	double discount = 0.0;
};

/*=============================================
				Bulk_quote
=============================================*/
class Bulk_quote : public Disc_quote {
public:
	Bulk_quote() = default;
	Bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	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;
}

/*=============================================
			Limited_bulk_quote
=============================================*/

class Limited_bulk_quote : public Disc_quote {
public:
	Limited_bulk_quote() = default;
	Limited_bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

private:
	size_t max_qty = 0;
	double discount = 0.0;
};

double Limited_bulk_quote::net_price(size_t cnt) const {
	if (cnt <= max_qty)
		return cnt * (1 - discount) * price;
	else
		return cnt * price;
}

16

见 15

17

不允许使用抽象类类型 “Disc_quote” 的对象

函数 double net_price(size_t) const 是纯虚拟函数

18

// 只有D公有地继承B时,用户代码才能使用D向B的转换
Base *p = &d1;	// 正确
p = &d2;		// 错误
p = &d3;		// 错误

// 派生类的派生类也是同理
// 只有DD公有地继承D时,用户代码才能使用DD向D的转换,然后再进行D到B的转换
p = &dd1;		// 正确
p = &dd2;		// 错误
p = &dd3;		// 错误

19

class Base {
public:
    int pub_mem;
protected:
    int prot_mem;
private:
    int priv_mem;
};

class Pub_Derv : public Base {
    void memfcn(Base& b) { b = *this; }
};

class Prot_Derv : protected Base {
    void memfcn(Base& b) { b = *this; }
};

class Priv_Derv : private Base {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Public : public Pub_Derv {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Protected : public Prot_Derv {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Private : public Priv_Derv {
    void memfcn(Base& b) { b = *this; }	// 只有这个是非法的
};

对于 Pub_Derv、Prot_Derv、Priv_Derv 这三个类,不论 D 以什么方式继承 B,D 的成员函数和友元都能使用派生类向基类的转换,所以对这三个类来说成员函数都是合法的

对于 Derived_from_Public、Derived_from_Protected、Derived_from_Private 来说,如果 D 继承 B 的方式是 public 或者 protected,DD(D 的派生类)才能使用派生类向基类的转换,所以只有 Derived_from_Private 的成员函数非法

20

21

图形

2D 图形:图形

3D 图形:图形

矩形:2D 图形

圆形:2D 图形

……

长方体:3D 图形

球体:3D 图形

……

22

23

#include <iostream>
#include "Quote.h"
using namespace std;

class Base {
public:
    virtual int fcn() {
        cout << "Base::fcn()\n";
        return 0;
    }
};

class D1 : public Base {
public:
    virtual int fcn() override {
        cout << "D1::fcn()\n";
        return 0;
    }
};

class D2 : public D1 {
public:
    virtual int fcn() override {
        cout << "D2::fcn()\n";
        return 0;
    }
};

int main() {
    Base bobj;
    D1 d1obj;
    D2 d2obj;

    Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
    bp1->fcn();
    bp2->fcn();
    bp3->fcn();
    return 0;
}

运行结果:

Base::fcn()
D1::fcn()
D2::fcn()

24

基类通常需要定义一个虚析构函数。虚析构函数可以确保编译器执行正确的析构函数版本(例如一个指针的静态类型与指向对象的动态类型不一致的时候)。

25

因为可以预见 Disc_quote 会有自己的派生类,如果去掉默认构造函数的话,因为我们为 Disc_quote 定义了一个接受 4 个参数的自定义构造函数,于是默认构造函数是删除的,Disc_quote 的派生类如 Bulk_quote 的默认构造函数也将会是删除的,因为 Bulk_quote 的 Disc_quote 基类部分无法被构造。

26

Quote.h:

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <utility>
using std::pair;

/*=============================================
					Quote
=============================================*/
class Quote {
public:
	//Quote() = default;
	Quote() : bookNo(""), price(0.0) {
		printf("Quote constructor\n");
	}
	//Quote(const Quote& rhs) = default;
	Quote(const Quote& rhs) : bookNo(rhs.bookNo), price(rhs.price) {
		printf("Quote copy constructor\n");
	}
	//Quote(Quote&& rhs) = default;
	Quote(Quote&& rhs) noexcept :
		bookNo(std::move(rhs.bookNo)), price(std::move(rhs.price)) {
		printf("Quote move constructor\n");
	}
	//Quote& operator=(const Quote& rhs) = default;
	Quote& operator=(const Quote& rhs) {
		printf("Quote copy assignment\n");
		bookNo = rhs.bookNo;
		price = rhs.price;
		return *this;
	}
	//Quote& operator=(Quote&& rhs) = default;
	Quote& operator=(Quote&& rhs) noexcept {
		printf("Quote move assignment\n");
		bookNo = rhs.bookNo;
		price = rhs.price;
		return *this;
	}
	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 ~Quote() {
		printf("Quote deconstructor\n");
	}

	virtual void debug() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Disc_quote
=============================================*/
class Disc_quote : public Quote {
public:
	Disc_quote() = default;
	Disc_quote(const string& book, double price, size_t qty, double disc) :
		Quote(book, price), quantity(qty), discount(disc) { }
	//virtual ~Disc_quote() = default;
	virtual ~Disc_quote() {
		printf("Disc_quote deconstructor\n");
	}
	
	virtual double net_price(size_t) const = 0;
	pair<size_t, double> discount_policy() const {
		return { quantity, discount };
	}

protected:
	size_t quantity = 0;
	double discount = 0.0;
};

/*=============================================
				Bulk_quote
=============================================*/
class Bulk_quote : public Disc_quote {
public:
	//Bulk_quote() = default;
	Bulk_quote() : Disc_quote(), min_qty(0), discount(0.0) {
		printf("Bulk_quote constructor\n");
	}
	//Bulk_quote(const Bulk_quote& rhs) = default;
	Bulk_quote(const Bulk_quote& rhs) :
		Disc_quote(rhs), min_qty(rhs.min_qty), discount(rhs.discount) {
		printf("Bulk_quote copy constructor\n");
	}
	//Bulk_quote(Bulk_quote&& rhs) = default;
	Bulk_quote(Bulk_quote&& rhs) noexcept :
		Disc_quote(std::move(rhs)),
		min_qty(std::move(rhs.min_qty)), discount(std::move(rhs.discount)) {
		printf("Bulk_quote move constructor\n");
	}
	//Bulk_quote& operator=(const Bulk_quote& rhs) = default;
	Bulk_quote& operator=(const Bulk_quote& rhs) {
		printf("Bulk_quote copy assignment\n");
		Disc_quote::operator=(rhs);
		min_qty = rhs.min_qty;
		discount = rhs.discount;
		return *this;
	}
	//Bulk_quote& operator=(Bulk_quote&& rhs) = default;
	Bulk_quote& operator=(Bulk_quote&& rhs) noexcept {
		printf("Bulk_quote move assignment\n");
		Disc_quote::operator=(std::move(rhs));
		min_qty = rhs.min_qty;
		discount = rhs.discount;
		return *this;
	}
	//virtual ~Bulk_quote() = default;
	virtual ~Bulk_quote() {
		printf("Bulk_quote deconstructor\n");
	}
	Bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	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;
}

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main() {
    Quote b1;
    Quote b2(b1);
    Quote b3(std::move(b1));
    b1 = b2;
    b1 = std::move(b2);
    Bulk_quote d1;
    Bulk_quote d2(d1);
    Bulk_quote d3(std::move(d1));
    d1 = d2;
    d1 = std::move(d2);
    return 0;
}

运行结果:

Quote move constructor
Quote copy assignment
Quote move assignment
Quote constructor
Bulk_quote constructor
Quote copy constructor
Bulk_quote copy constructor
Quote copy constructor
Bulk_quote move constructor
Bulk_quote copy assignment
Quote copy assignment
Bulk_quote move assignment
Quote copy assignment
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Quote deconstructor
Quote deconstructor
Quote deconstructor

27

在类中加入

using Disc_quote::Disc_quote;

标签:27,15,quote,price,C++,double,Bulk,Quote,const
来源: https://blog.csdn.net/G0rgeoustray/article/details/120753386

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有