C++ Primer第五版_第十五章习题答案(21~30)
文章目录
- 练习15.21
- 练习15.22
- 练习15.23
- 练习15.24
- 练习15.25
- 练习15.26
- Quote
- Bulk_quote
- 练习15.27
- 练习15.28
- 练习15.29
- 练习15.30
- basket.h
- basket.cpp
- main.cpp
练习15.21
从下面这些一般性抽象概念中任选一个(或者选一个你自己的),将其对应的一组类型组织成一个继承体系:
(a) 图形文件格式(如gif、tiff、jpeg、bmp)
(b) 图形基元(如方格、圆、球、圆锥)
(c) C++语言中的类型(如类、函数、成员函数)
练习15.22
对于你在上一题中选择的类,为其添加函数的虚函数及公有成员和受保护的成员。
练习15.23
假设第550页的 D1 类需要覆盖它继承而来的 fcn 函数,你应该如何对其进行修改?如果你修改之后 fcn 匹配了 Base 中的定义,则该节的那些调用语句将如何解析?
移除 int 参数。
练习15.24
哪种类需要虚析构函数?虚析构函数必须执行什么样的操作?
基类通常应该定义一个虚析构函数。
练习15.25
我们为什么为 Disc_quote 定义一个默认构造函数?如果去掉该构造函数的话会对 Bulk_quote 的行为产生什么影响?
因为Disc_quote的默认构造函数会运行Quote的默认构造函数,而Quote默认构造函数会完成成员的初始化工作。 如果去除掉该构造函数的话,Bulk_quote的默认构造函数而无法完成Disc_quote的初始化工作。
练习15.26
定义 Quote 和 Bulk_quote 的拷贝控制成员,令其与合成的版本行为一致。为这些成员以及其他构造函数添加打印状态的语句,使得我们能够知道正在运行哪个程序。使用这些类编写程序,预测程序将创建和销毁哪些对象。重复实验,不断比较你的预测和实际输出结果是否相同,直到预测完全准确再结束。
Quote
#ifndef QUOTE_H
#define QUOTE_H
#include <string>
#include <iostream>
class Quote
{
friend bool operator !=(const Quote& lhs, const Quote& rhs);
public:
Quote() { std::cout << "default constructing Quote\n"; }
Quote(const std::string &b, double p) :
bookNo(b), price(p)
{
std::cout << "Quote : constructor taking 2 parameters\n";
}
// copy constructor
Quote(const Quote& q) : bookNo(q.bookNo), price(q.price)
{
std::cout << "Quote: copy constructing\n";
}
// move constructor
Quote(Quote&& q) noexcept : bookNo(std::move(q.bookNo)), price(std::move(q.price))
{ std::cout << "Quote: move constructing\n"; }
// copy =
Quote& operator =(const Quote& rhs)
{
if (*this != rhs)
{
bookNo = rhs.bookNo;
price = rhs.price;
}
std::cout << "Quote: copy =() \n";
return *this;
}
// move =
Quote& operator =(Quote&& rhs) noexcept
{
if (*this != rhs)
{
bookNo = std::move(rhs.bookNo);
price = std::move(rhs.price);
}
std::cout << "Quote: move =!!!!!!!!! \n";
return *this;
}
std::string isbn() const { return bookNo; }
virtual double net_price(std::size_t n) const { return n * price; }
virtual void debug() const;
virtual ~Quote()
{
std::cout << "destructing Quote\n";
}
private:
std::string bookNo;
protected:
double price = 10.0;
};
bool inline
operator !=(const Quote& lhs, const Quote& rhs)
{
return lhs.bookNo != rhs.bookNo
&&
lhs.price != rhs.price;
}
#endif // QUOTE_H
Bulk_quote
#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "Disc_quote.h"
#include <iostream>
class Bulk_quote : public Disc_quote
{
public:
Bulk_quote() { std::cout << "default constructing Bulk_quote\n"; }
Bulk_quote(const std::string& b, double p, std::size_t q, double disc) :
Disc_quote(b, p, q, disc)
{
std::cout << "Bulk_quote : constructor taking 4 parameters\n";
}
// copy constructor
Bulk_quote(const Bulk_quote& bq) : Disc_quote(bq)
{
std::cout << "Bulk_quote : copy constructor\n";
}
// move constructor
Bulk_quote(Bulk_quote&& bq) : Disc_quote(std::move(bq)) noexcept
{
std::cout << "Bulk_quote : move constructor\n";
}
// copy =()
Bulk_quote& operator =(const Bulk_quote& rhs)
{
Disc_quote::operator =(rhs);
std::cout << "Bulk_quote : copy =()\n";
return *this;
}
// move =()
Bulk_quote& operator =(Bulk_quote&& rhs) noexcept
{
Disc_quote::operator =(std::move(rhs));
std::cout << "Bulk_quote : move =()\n";
return *this;
}
double net_price(std::size_t n) const override;
void debug() const override;
~Bulk_quote() override
{
std::cout << "destructing Bulk_quote\n";
}
};
#endif // BULK_QUOTE_H
练习15.27
重新定义你的 Bulk_quote 类,令其继承构造函数。
#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "disc_quote.h"
#include <iostream>
class Bulk_quote : public Disc_quote
{
public:
Bulk_quote() { std::cout << "default constructing Bulk_quote\n"; }
// changed the below to the inherited constructor for ex15.27.
// rules: 1. only inherit from the direct base class.
// 2. default, copy and move constructors can not inherit.
// 3. any data members of its own are default initialized.
// 4. the rest details are in the section section 15.7.4.
/*
Bulk_quote(const std::string& b, double p, std::size_t q, double disc) :
Disc_quote(b, p, q, disc) { std::cout << "Bulk_quote : constructor taking 4 parameters\n"; }
*/
using Disc_quote::Disc_quote;
// copy constructor
Bulk_quote(const Bulk_quote& bq) : Disc_quote(bq)
{
std::cout << "Bulk_quote : copy constructor\n";
}
// move constructor
Bulk_quote(Bulk_quote&& bq) : Disc_quote(std::move(bq))
{
std::cout << "Bulk_quote : move constructor\n";
}
// copy =()
Bulk_quote& operator =(const Bulk_quote& rhs)
{
Disc_quote::operator =(rhs);
std::cout << "Bulk_quote : copy =()\n";
return *this;
}
// move =()
Bulk_quote& operator =(Bulk_quote&& rhs)
{
Disc_quote::operator =(std::move(rhs));
std::cout << "Bulk_quote : move =()\n";
return *this;
}
double net_price(std::size_t n) const override;
void debug() const override;
~Bulk_quote() override
{
std::cout << "destructing Bulk_quote\n";
}
};
#endif // BULK_QUOTE_H
练习15.28
定义一个存放 Quote 对象的 vector,将 Bulk_quote 对象传入其中。计算 vector 中所有元素总的 net_price。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"
int main()
{
/**
* @brief ex15.28 outcome == 9090
*/
std::vector<Quote> v;
for (unsigned i = 1; i != 10; ++i)
v.push_back(Bulk_quote("sss", i * 10.1, 10, 0.3));
double total = 0;
for (const auto& b : v)
{
total += b.net_price(20);
}
std::cout << total << std::endl;
std::cout << "======================\n\n";
/**
* @brief ex15.29 outccome == 6363
*/
std::vector<std::shared_ptr<Quote>> pv;
for (unsigned i = 1; i != 10; ++i)
pv.push_back(std::make_shared<Bulk_quote>(Bulk_quote("sss", i * 10.1, 10, 0.3)));
double total_p = 0;
for (auto p : pv)
{
total_p += p->net_price(20);
}
std::cout << total_p << std::endl;
return 0;
}
练习15.29
再运行一次你的程序,这次传入 Quote 对象的 shared_ptr 。如果这次计算出的总额与之前的不一致,解释为什么;如果一直,也请说明原因。
因为智能指针导致了多态性的产生,所以这次计算的总额不一致。
练习15.30
编写你自己的 Basket 类,用它计算上一个练习中交易记录的总价格。
basket.h
#ifndef BASKET_H
#define BASKET_H
#include "quote.h"
#include <set>
#include <memory>
// a basket of objects from Quote hierachy, using smart pointers.
class Basket
{
public:
// copy verison
void add_item(const Quote& sale)
{
items.insert(std::shared_ptr<Quote>(sale.clone()));
}
// move version
void add_item(Quote&& sale)
{
items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));
}
double total_receipt(std::ostream& os) const;
private:
// function to compare needed by the multiset member
static bool compare(const std::shared_ptr<Quote>& lhs,
const std::shared_ptr<Quote>& rhs)
{
return lhs->isbn() < rhs->isbn();
}
// hold multiple quotes, ordered by the compare member
std::multiset<std::shared_ptr<Quote>, decltype(compare)*>
items{ compare };
};
#endif // BASKET_H
basket.cpp
#include "basket.h"
double Basket::total_receipt(std::ostream &os) const
{
double sum = 0.0;
for (auto iter = items.cbegin(); iter != items.cend();
iter = items.upper_bound(*iter))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// @note this increment moves iter to the first element with key
// greater than *iter.
{
sum += print_total(os, **iter, items.count(*iter));
} // ^^^^^^^^^^^^^ using count to fetch
// the number of the same book.
os << "Total Sale: " << sum << std::endl;
return sum;
}
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <fstream>
#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"
#include "basket.h"
int main()
{
Basket basket;
for (unsigned i = 0; i != 10; ++i)
basket.add_item(Bulk_quote("Bible", 20.6, 20, 0.3));
for (unsigned i = 0; i != 10; ++i)
basket.add_item(Bulk_quote("C++Primer", 30.9, 5, 0.4));
for (unsigned i = 0; i != 10; ++i)
basket.add_item(Quote("CLRS", 40.1));
std::ofstream log("log.txt", std::ios_base::app | std::ios_base::out);
basket.total_receipt(log);
return 0;
}