C++Primer 第十五章 面向对象程序设计 习题答案

15.1

对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数。

15.2

派生类可以访问基类的保护成员,但是不能访问基类的私有成员。同时二者都禁止其他对象访问。

15.3

.h

#pragma once
#include<string>
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;//书籍的ISBN编号
protected:
	double price = 0.0; //普通状态下不打折的价格
};
class Bulk_quote:public Quote
{
public:
	double net_price(std::size_t)const override;
};

.cpp

#include"Quote.h"
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

(a)错误,一个类不能派生它本身
(b)正确
©错误,声明不用写出它的派生列表

15.5

#pragma once
#include"Quote.h"
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(std::size_t cnt)const
{
	if (cnt >= min_qty)
		return cnt * (1 - discount)*price;
	else
		return cnt * price;
}

15.6

#include"Quote.h"
#include"Bulk_quote.h"
#include<iostream>
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;
}
int main()
{
	Quote q("114514",11);
	Bulk_quote b("114514",11,10,0.1);
	print_total(std::cout, q, 11);
	print_total(std::cout, b, 11);
	return 0;
}

15.7

double Bulk_quote::net_price(std::size_t cnt)const
{
	if (cnt >= min_qty)
		return min_qty * (1 - discount)*price+(cnt- min_qty)*price;
	else
		return cnt * (1 - discount)*price;
}

15.8

表达式的静态类型在编译时总是已知的,它时变量声明时的类型或表达式生成的类型;动态类型则是变量或表达式表示的内存中对象的类型,直到运行时才可知

15.9

Bulk_quote bulk;
Quote *quote_pointer = &bulk;// 指针
Quote &quote_reference = bulk; // 引用
Quote quote= bulk; // 赋值

15.10

read接收的形参时istream&,因此可以引入istream的派生类ifstream作为动态类型。

15.11

base:

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

bulk:

void Bulk_quote::debug()const
{
	std::cout << "min_qty:" << min_qty << " discount:" << discount << std::endl;
}

15.12

有必要,因为两者并不冲突,override时复写继承的基类虚函数,final表示禁止自己的虚函数被禁止。

15.13

base:作为虚函数输出基类的私有成员
derived:作为成员函数调用自身,会导致无限递归.
修改:表明作用域

void print(ostream &os) {
base::print(os);
os<<" "<<i;
}

15.14

(a)base;
(b)derived;
©base;
(d)base;
(e)base;
(f)derived;

15.15

Disc_quote.h

#pragma once
#include"Quote.h"
// 抽象基类
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; //表示折扣的小数值
};

bulk.h

#pragma once
#include"Quote.h"
#include"Disc_quote.h"
class Bulk_quote :public Disc_quote
{
public:
	Bulk_quote() = default;
	Bulk_quote(const std::string&book, double p, std::size_t qty, double disc):
		Disc_quote(book,p,qty,disc){}
	double net_price(std::size_t)const override;
	virtual void debug()const override;
private:
	//std::size_t min_qty = 0; //使用折扣政策的最低购买量
	//double discount = 0.0; //小数表示的折扣额
};

15.16

double Bulk_quote::net_price(std::size_t cnt)const
{
	if (cnt >= quantity)
		return quantity * (1 - discount)*price+(cnt- quantity)*price;
	else
		return cnt * (1 - discount)*price;
}

15.17

代码	说明	文件	行	禁止显示状态
E0322	不允许使用抽象类类型 "Disc_quote" 的对象:

15.18

Base *p=&d1; 合法
p=&d2; 不合法,用户代码不能使用该转换
p=&d3; 不合法,同上
p=&dd1; 合法
p=&dd2; 不合法,同上
p=&dd3; 不合法,同上

15.19

base 合法
不管D以什么方式继承B,D的成员函数和友元都能使用派生类向基类的转换,所以Pub_Derv,Priv_Derv,合法
如果D继承B的方式时公有的或保护的,则D的派生类的成员和友元可以使用D向B的转换,所以drived_from_public合法,drived_from_private非法。

15.21&22

#include<iostream>
#include<string>
class Shape
{
public:
	virtual double area()const = 0;
	virtual double perimiter()const = 0;
	virtual ~Shape() = default;
private:
	std::string name;
};
class Rectangle: public Shape
{
private:
	Rectangle(double l,double w):
		length(l),width(w){}
	double area()const override { return length * width; }
	double perimiter()const override { return 2 * (length + width); }
private:
	double length;
	double width;
};
class Circle :public Shape
{
public:
	Circle(double r) :radius(r) {}
	double area()const override
	{
		return radius * radius * 3.14;
	}
	double perimiter()const override
	{
		return 2 * radius * 3.14;
	}
protected:
	double radius;
};
class spshere :public Circle
{
public:
	spshere(double r) :Circle(r) {}
	double area()const override
	{
		return 4 * 3.14 * radius, radius;
	}
	double volume()const
	{
		return 3 / 4 * 3.14 * radius * radius * radius;
	}
};
class Circle_Cone : public Circle
{
public:
	double volume() const
	{
		return 3.14 * radius * radius * height;
	}
private:
	double height;
}; 
int main()
{

}

15.23

int fcn()overrive{}
bp2->fcn(); 将会调用D1::fcn

15.24

基类需要虚析构函数

15.25

因为基类的默认构造函数会影响到派生类的默认初始化;
如果去除掉以后Bulk_quote将无法进行自己的默认构造函数从而初始化。

15.26

quote.h

#pragma once
#include<string>
#include<iostream>
class Quote
{
	friend bool operator!=(const Quote&lhs, const Quote&rhs);
public:
	Quote() { std::cout << "基类默认构造函数:" << std::endl; }
	Quote(const std::string &book, double sales_price) :
		bookNo(book), price(sales_price) {
		std::cout << "基类带两个参数的构造函数:" << std::endl;
	}
	Quote(const Quote&q):bookNo(q.bookNo),price(q.price)
	{ std::cout << "基类拷贝构造函数:" << std::endl; }
	Quote(Quote&& q):bookNo(std::move(q.bookNo)),price(std::move(q.price))
	{
		std::cout << "基类移动构造函数:" << std::endl;}
	Quote& operator=(const Quote&rhs) {
		if (*this != rhs) {
			bookNo = rhs.bookNo;
			price = rhs.price;
		}
		std::cout << "基类拷贝赋值运算符:" << std::endl;
		return *this;
	}
	Quote& operator=(Quote&&rhs)noexcept {
		if (*this != rhs)
		{
			bookNo = std::move(rhs.bookNo);
			price = std::move(rhs.price);
		}
		std::cout << "基类移动赋值运算符:" << std::endl;
		return *this;
	}

	std::string isbn()const { return bookNo; }
	virtual double net_price(std::size_t n)const { return n * price; } //返回书籍的实际销售价格
	virtual void debug()const {
		std::cout << "INBN():" << bookNo << " price:" << price << std::endl;}
	virtual ~Quote() { std::cout << "基类析构函数:" << std::endl; }
private:
	std::string bookNo;//书籍的ISBN编号
protected:
	double price = 0.0; //普通状态下不打折的价格
};
bool operator!=(const Quote&lhs, const Quote&rhs)
{
	return lhs.bookNo != rhs.bookNo&&lhs.price != rhs.price;
}

Bulk_quote.h

#pragma once
#include"Quote.h"
#include"Disc_quote.h"
class Bulk_quote :public Disc_quote
{
public:
	//五件套
	Bulk_quote() { std::cout << "孙子类默认构造函数:" << std::endl; }
	Bulk_quote(const std::string&book, double p, std::size_t qty, double disc):
		Disc_quote(book, p, qty, disc) {
		std::cout << "孙子类带四个参数构造函数:" << std::endl;}
	Bulk_quote(const Bulk_quote&b):Disc_quote(b){
		std::cout << "孙子类拷贝构造函数:" << std::endl;}
	Bulk_quote& operator=(const Bulk_quote&rhs) {
		Disc_quote::operator=(rhs);
		std::cout << "孙子类拷贝赋值运算符:" << std::endl;}
	Bulk_quote(Bulk_quote&&b)noexcept:Disc_quote(std::move(b)) {
		std::cout << "孙子类移动构造函数:" << std::endl;}
	Bulk_quote& operator=(Bulk_quote&&rhs)noexcept {
		Disc_quote::operator=(std::move(rhs));
		std::cout << "孙子类移动赋值运算符:" << std::endl;}
	~Bulk_quote() override{
		std::cout << "孙子类析构函数:" << std::endl;}

	double net_price(std::size_t)const override;
	virtual void debug()const override;
private:
};
//如果达到一定购买量,就可以享受折扣
double Bulk_quote::net_price(std::size_t cnt)const
{
	if (cnt >= quantity)
		return quantity * (1 - discount)*price+(cnt- quantity)*price;
	else
		return cnt * (1 - discount)*price;
}
//void Bulk_quote::debug()const
//{
//	std::cout << "min_qty:" << min_qty << " discount:" << discount << std::endl;
//}

15.27

	/*Bulk_quote(const std::string&book, double p, std::size_t qty, double disc):
		Disc_quote(book, p, qty, disc) {
		std::cout << "孙子类带四个参数构造函数:" << std::endl;}*/
	using Disc_quote::Disc_quote;

15.28

Quote.h

#pragma once
#include<string>
#include<iostream>
class Quote
{
	friend bool operator!=(const Quote&lhs, const Quote&rhs);
public:
	Quote() { std::cout << "基类默认构造函数:" << std::endl; }
	Quote(const std::string &book, double sales_price) :
		bookNo(book), price(sales_price) {
		std::cout << "基类带两个参数的构造函数:" << std::endl;
	}
	Quote(const Quote&q):bookNo(q.bookNo),price(q.price)
	{ std::cout << "基类拷贝构造函数:" << std::endl; }
	Quote(Quote&& q):bookNo(std::move(q.bookNo)),price(std::move(q.price))
	{
		std::cout << "基类移动构造函数:" << std::endl;}
	Quote& operator=(const Quote&rhs) {
		if (*this != rhs) {
			bookNo = rhs.bookNo;
			price = rhs.price;
		}
		std::cout << "基类拷贝赋值运算符:" << std::endl;
		return *this;
	}
	Quote& operator=(Quote&&rhs)noexcept {
		if (*this != rhs)
		{
			bookNo = std::move(rhs.bookNo);
			price = std::move(rhs.price);
		}
		std::cout << "基类移动赋值运算符:" << std::endl;
		return *this;
	}

	std::string isbn()const { return bookNo; }
	virtual double net_price(std::size_t n)const { return n * price; } //返回书籍的实际销售价格
	virtual void debug()const {
		std::cout << "INBN():" << bookNo << " price:" << price << std::endl;}
	virtual ~Quote() { std::cout << "基类析构函数:" << std::endl; }
private:
	std::string bookNo;//书籍的ISBN编号
protected:
	double price = 0.0; //普通状态下不打折的价格
};
bool inline operator!=(const Quote&lhs, const Quote&rhs)
{
	return lhs.bookNo != rhs.bookNo&&lhs.price != rhs.price;
}

Disc_quote.h

#pragma once
#include"Quote.h"
// 抽象基类
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) {
		std::cout << "子类带有四个参数的构造函数:" << std::endl;}
	~Disc_quote()
	{
		std::cout << "子类析构函数:" << std::endl;}
	double net_price(std::size_t)const = 0; //纯虚函数
protected:
	std::size_t quantity = 0; //折扣适用的购买量
	double discount = 0.0; //表示折扣的小数值
};

Bulk_quote.h

#pragma once
#include"Quote.h"
#include"Disc_quote.h"
class Bulk_quote :public Disc_quote
{
public:
	//五件套
	Bulk_quote() = default;
	/*Bulk_quote(const std::string&book, double p, std::size_t qty, double disc):
		Disc_quote(book, p, qty, disc) {
		std::cout << "孙子类带四个参数构造函数:" << std::endl;}*/
	using Disc_quote::Disc_quote;

	Bulk_quote(const Bulk_quote&b):Disc_quote(b){
		std::cout << "孙子类拷贝构造函数:" << std::endl;}
	Bulk_quote& operator=(const Bulk_quote&rhs) {
		Disc_quote::operator=(rhs);
		std::cout << "孙子类拷贝赋值运算符:" << std::endl;
		return *this;}
	Bulk_quote(Bulk_quote&&b)noexcept:Disc_quote(std::move(b)) {
		std::cout << "孙子类移动构造函数:" << std::endl;}
	Bulk_quote& operator=(Bulk_quote&&rhs)noexcept {
		Disc_quote::operator=(std::move(rhs));
		std::cout << "孙子类移动赋值运算符:" << std::endl;}
	~Bulk_quote() override{
		std::cout << "孙子类析构函数:" << std::endl;}

	double net_price(std::size_t)const override;
	virtual void debug()const override;
private:
};
//如果达到一定购买量,就可以享受折扣
double Bulk_quote::net_price(std::size_t cnt)const
{
	if (cnt >= quantity)
		return quantity * (1 - discount)*price+(cnt- quantity)*price;
	else
		return cnt * (1 - discount)*price;
}
void Bulk_quote::debug()const
{
	//std::cout << "min_qty:" << min_qty << " discount:" << discount << std::endl;
}

main.cpp

#include"Quote.h"
#include"Bulk_quote.h"
#include"Disc_quote.h"
#include<memory>
#include<vector>
int main()
{
	 std::vector<std::shared_ptr<Quote>>basket;
	 basket.push_back(std::make_shared<Bulk_quote>("No-123", 30, 20, 0.2));
	double total = 0.0;
	for (const auto&i : basket)
	{
		total += i->net_price(20);
	}
	std::cout << total << std::endl;
/*基类带两个参数的构造函数:
子类带有四个参数的构造函数:
480
孙子类析构函数:
子类析构函数:
基类析构函数:*/
}

15.29

不一致是因为前者是值传递,因此调用的是基类的net_price函数;后者是地址传递,调用的是Bulk_quote的net_price函数。

15.30

.h

#pragma once
#include"Quote.h"
#include<memory>
#include<set>
class Basket
{
public:
	//使用默认的构造和拷贝函数
	//void add_itme(const std::shared_ptr<Quote> &sale) { items.insert(sale); }
	void add_item(const Quote& sale)
	{items.insert(std::shared_ptr<Quote>(sale.clone()));}
	void add_item(Quote&& sale)
	{items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));}
	// 打印每本书的总价和购物篮中所有书的总价
	double total_receipt(std::ostream&)const;
private:
	//该函数用于比较shared_ptr,multiset会引用他
	static bool compare(const std::shared_ptr<Quote> &lhs, const std::shared_ptr<Quote> &rhs)
	{return lhs->isbn() < rhs->isbn();}
	//multiset保存多个报价,按照compare成员排序
	std::multiset<std::shared_ptr<Quote>, decltype(compare)*> items{ compare };
};

.cpp

#include"Quote.h"
#include"Basket.h"
double Basket::total_receipt(std::ostream&os)const
{
	double sum = 0.0; //总价格
	// upper_bound返回一个迭代器,指向元素的尾后位置
	for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter))
	{
		sum += print_total(os, **iter, items.count(*iter));//**iter是一个quote对象
	}
	os << "Total sale:" << sum << std::endl;
	return sum;
}

15.31

(a)OrQuery, AndQuery, NotQuery, WordQuery
(b)同上
©OrQuery, AndQuery, WordQuery

15.32

拷贝:会调用合成的拷贝构造函数,拷贝Query的数据成员,成员q由于是shared_ptr,其引用计数会加1.
移动:会调用合成移动构造函数。新对象的shared_ptr的引用计数加1,原对象的shared_ptr的引用计数减1。
赋值:调用合成的赋值函数,结果与拷贝操作相同。
销毁:调用合成的析构函数,shared_ptr的引用计数减1,如果其引用计数减至0,则会释放它指向的内存

15.33

query_base是一个抽象类,因此无法使用抽象类类型的对象;
可以通过它的子类的对象来进行这些操作,结果同上。

15.34

15.35

query.h

Skip to content
Search or jump to…
Pull requests
Issues
Codespaces
Marketplace
Explore
 
@whitenighttttt 
Mooophy
/
Cpp-Primer
Public
Fork your own copy of Mooophy/Cpp-Primer
Code
Issues
106
Pull requests
90
Actions
Projects
Wiki
Security
Insights
Cpp-Primer/ch15/ex15.34.35.36.38/query.h
@Mooophy
Mooophy change comment mark to // for .h files
…
Latest commit b36f6d8 on Aug 25, 2015
 History
 2 contributors
@pezy@Mooophy
55 lines (47 sloc)  1.26 KB

#ifndef QUERY_H
#define QUERY_H

#include <iostream>
#include <string>
#include <memory>
#include "query_base.h"
#include "queryresult.h"
#include "textquery.h"
#include "wordquery.h"
class Query
{
    friend Query operator~(const Query&);
    friend Query operator|(const Query&, const Query&);
    friend Query operator&(const Query&, const Query&);
public:
    // build a new WordQuery
    Query(const std::string& s) : q(new WordQuery(s))
    {
        std::cout << "Query::Query(const std::string& s) where s="+s+"\n";
    }
    QueryResult eval(const TextQuery& t) const
    { return q->eval(t); }
    std::string rep() const
    {
        std::cout << "Query::rep() \n";
        return q->rep();
    }

private:
    // constructor only for friends
    Query(std::shared_ptr<Query_base> query) :
        q(query)
    {
        std::cout << "Query::Query(std::shared_ptr<Query_base> query)\n";
    }
    std::shared_ptr<Query_base> q;
};

inline std::ostream&
operator << (std::ostream& os, const Query& query)
{
    return os << query.rep();
}

#endif // QUERY_H


query_base.h

#ifndef QUERY_BASE_H
#define QUERY_BASE_H
#include "textquery.h"
#include "queryresult.h"
class Query_base
{
    friend class Query;
protected:
    using line_no = TextQuery::line_no; 
    virtual ~Query_base() = default;
private:
    virtual QueryResult eval(const TextQuery&) const = 0;
    virtual std::string rep() const = 0;
};
#endif // QUERY_BASE_H
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值