第十五章 面向对象程序设计
15.1
基类希望其派生类进行覆盖的函数,通过在其成员函数的声明语句之前加上关键字virtual使得该函数执行动态绑定。
基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明成虚函数。通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此。
15.2
private:基类自身和友元可以访问。
protect:基类自身,友元,派生类可以访问。
15.3
#ifndef CP5_EX15_03_QUOTE_H_
#define CP5_EX15_03_QUOTE_H_
#include <string>
#include <iostream>
inline namespace EX03 {
using std::string;
using std::ostream; using std::endl;
class Quote {
public:
Quote() = default;
Quote(string const& b, double p) : bookNo(b), price(p) { }
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;
};
double print_total(ostream& os, Quote const& item, size_t n) {
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
return ret;
}
}
#endif // CP5_EX15_03_QUOTE_H_
15.4
(a) 不正确,一个类不能派生自它自己。
(b) 正确。
(c) 不正确,派生类的声明与其他类差别不大,声明中包含类名但是不包含它的派生列表。
15.5
#ifndef CP5_EX15_05_BULK_QUOTE_H_
#define CP5_EX15_05_BULK_QUOTE_H_
#include "ex15_03_Quote.h"
#include <string>
namespace EX05 {
using std::string;
using namespace EX03;
class Bulk_quote : public Quote {
public:
Bulk_quote() = default;
Bulk_quote(string const& book, double p, size_t qty, double disc) : Quote(book, p), min_qty(qty), discount(disc) {}
virtual double net_price(size_t cnt) const override {
if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
protected:
size_t min_qty = 0;
double discount = 0.0;
};
}
#endif // CP5_EX15_05_BULK_QUOTE_H_
15.6
#include "ex15_03_Quote.h"
#include "ex15_05_Bulk_quote.h"
#include "ex15_07_Limit_quote.h"
#include "ex15_11_Quote.h"
#include "ex15_11_Bulk_quote.h"
#include "ex15_11_Limit_quote.h"
#include "ex15_15_Disc_quote.h"
#include "ex15_15_Bulk_quote.h"
#include "ex15_16_Limit_quote.h"
#include "ex15_20_Base.h"
#include "ex15_21_GeomtricPrimitives.h"
#include "ex15_26_Quote.h"
#include "ex15_26_Bulk_quote.h"
#include "ex15_27_Bulk_quote.h"
#include "ex15_30_Basket.h"
int main()
{
cout << "\n===== ex03 =====" << endl;
EX03::Quote quote_03("0-201-78345-X", 23.8);
EX03::print_total(cout, quote_03, 3);
cout << "\n===== ex05 =====" << endl;
EX05::Bulk_quote bulk_quote("0-201-78345-X", 23.8, 3, 0.5);
EX03::print_total(cout, bulk_quote, 4);
cout << "\n===== ex07 =====" << endl;
EX07::Limit_quote limit_quote("0-201-78345-X", 23.8, 3, 5, 0.5);
EX03::print_total(cout, limit_quote, 6);
cout << "\n===== ex11 =====" << endl;
EX11::Quote quote_11("0-201-82470-1", 50);
EX11::Bulk_quote bulk_quote_11("0-201-82470-1", 50, 5, .19);
EX11::Limit_quote limit_quote_11("0-201-82470-1", 50, 5, 10, .19);
quote_11.debug();
bulk_quote_11.debug();
limit_quote_11.debug();
cout << "\n===== ex15 =====" << endl;
EX15::Bulk_quote bulk_quote_15("0-201-82470-1", 50, 5, .19);
EX03::print_total(cout, bulk_quote_15, 6);
cout << "\n===== ex16 =====" << endl;
EX16::Limit_quote limit_quote_16("0-201-82470-1", 50, 5, 10, .19);
EX03::print_total(cout, limit_quote_16, 14);
cout << "\n===== ex20 =====" << endl;
//EX20::Pub_Derv d1;
//EX20::Priv_Derv d2;
//EX20::Prot_Derv d3;
//EX20::Derived_from_Public dd1;
//EX20::Derived_from_Private dd2;
//EX20::Derived_from_Protected dd3;
//EX20::Base *p = &d1;
// p = &d2; // error: inaccessible
// p = &d3; // error: inaccessible
//p = &dd1;
// p = &dd2; // error: inaccessible
// p = &dd3; // error: inaccessible
cout << "\n===== ex21 =====" << endl;
EX21::Box box;
cout << box.shape_name();
box.resize_by_percentage(4.f);
cout << "'s volume = " << box.volume() << endl;
EX21::Circle circle;
cout << circle.shape_name();
circle.resize_by_percentage(2.f);
cout << "'s area = " << circle.area() << endl;
EX21::Sphere sphere;
cout << sphere.shape_name();
sphere.resize_by_percentage(2.f);
cout << "'s volume = " << sphere.volume() << endl;
EX21::Cone cone;
cout << cone.shape_name();
cone.resize_by_percentage(2.f);
cout << "'s volume = " << cone.volume() << endl;
cout << "\n===== ex26 =====" << endl;
{
EX26::Quote quote_26;
EX26::Quote quote_26_p("0-201-78345-X", 23.8);
EX26::Quote quote_26_cp(quote_26_p);
EX26::Quote quote_26_mv(std::move(quote_26_p));
cout << "------ISBN: price------" << endl;
cout << quote_26.isbn() << ": " << quote_26.net_price(3) << endl;
cout << quote_26_cp.isbn() << ": " << quote_26_cp.net_price(3) << endl;
cout << quote_26_mv.isbn() << ": " << quote_26_mv.net_price(3) << endl;
cout << "-----------------------" << endl;
EX26::Bulk_quote bulk_26;
EX26::Bulk_quote bulk_26_p("0-201-78345-X", 23.8, 3, 0.5);
EX26::Bulk_quote bulk_26_cp(bulk_26_p);
EX26::Bulk_quote bulk_26_mv(std::move(bulk_26_p));
cout << "------ISBN: price------" << endl;
cout << bulk_26.isbn() << ": " << bulk_26.net_price(3) << endl;
cout << bulk_26_cp.isbn() << ": " << bulk_26_cp.net_price(3) << endl;
cout << bulk_26_mv.isbn() << ": " << bulk_26_mv.net_price(3) << endl;
cout << "-----------------------" << endl;
}
cout << "\n===== ex27 =====" << endl;
EX27::Bulk_quote bulk_quote_27("0-201-82470-1", 50, 5, .19);
EX03::print_total(std::cout, bulk_quote_15, 6);
cout << "\n===== ex30 =====" << endl;
EX30::Basket bsk;
for (size_t i = 0; i != 10; ++i) {
bsk.add_item(EX30::Bulk_quote("Bible", 20.5, 5, 0.2));
bsk.add_item(EX30::Bulk_quote("CppPrimer", 30.5, 10, 0.5));
bsk.add_item(EX30::Quote("CLRS", 40.5));
}
bsk.total_receipt(std::cout);
}
15.7
#ifndef CP5_EX15_07_LIMIT_QUOTE_H_
#define CP5_EX15_07_LIMIT_QUOTE_H_
#include "ex15_05_Bulk_quote.h"
#include <string>
namespace EX07 {
using namespace EX05;
using std::string;
class Limit_quote : public Bulk_quote {
public:
Limit_quote() = default;
Limit_quote(string const& book, double p, size_t min, size_t max, double dist) : Bulk_quote(book, p, min, dist), max_qty(max) {}
double net_price(size_t cnt) const override {
if (cnt > max_qty) return max_qty * (1 - discount) * price + (cnt - max_qty) * price;
else if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
private:
size_t max_qty = 0;
};
}
#endif // LIMIT_QUOTE_H_
15.8
静态类型:在编译时已知的,它是变量声明时的类型或表达式生成的类型。
动态类型:变量或表达式表示的内存中对象的类型。动态类型直达运行是才可知。
15.9
指向基类的指针或引用可以绑定到派生类对象上。在这种情况下,静态类型是对基类的引用或指针,而动态类型是对派生类的引用或指针。
15.10
该函数接收一个从istream派生的ifstream,因此ifstream是''一个''istream.
15.11
Quote
#ifndef CP5_EX15_11_QUOTE_H_
#define CP5_EX15_11_QUOTE_H_
#include <string>
#include <iostream>
inline namespace EX11 {
using std::string;
using std::ostream; using std::endl; using std::cout;
class Quote {
public:
Quote() = default;
Quote(string const& b, double p) : bookNo(b), price(p) { }
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const { return n * price; }
virtual void debug() const { cout << "data members: \n" << "\tbookNo: " << bookNo << "\tprice: " << price << endl; }
virtual ~Quote() = default;
private:
string bookNo;
protected:
double price = 0.0;
};
double print_total(ostream& os, Quote const& item, size_t n) {
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
return ret;
}
}
#endif // CP5_EX15_11_QUOTE_H_
Bulk_quote
#ifndef CP5_EX15_11_BULK_QUOTE_H_
#define CP5_EX15_11_BULK_QUOTE_H_
#include "ex15_11_Quote.h"
#include <string>
namespace EX11 {
using std::string;
class Bulk_quote : public Quote {
public:
Bulk_quote() = default;
Bulk_quote(string const& book, double p, size_t qty, double disc) : Quote(book, p), min_qty(qty), discount(disc) {}
virtual double net_price(size_t cnt) const override {
if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
virtual void debug() const override {
Quote::debug();
cout << "\tminqty: " << min_qty << "\tdiscount: " << discount << endl;
}
protected:
size_t min_qty = 0;
double discount = 0.0;
};
}
#endif // CP5_EX15_11_BULK_QUOTE_H_
limit_quote
#ifndef CP5_EX15_11_LIMIT_QUOTE_H_
#define CP5_EX15_11_LIMIT_QUOTE_H_
#include "ex15_11_Bulk_quote.h"
#include <string>
namespace EX11 {
using std::string;
using std::cout; using std::endl;
class Limit_quote : public Bulk_quote {
public:
Limit_quote() = default;
Limit_quote(string const& book, double p, size_t min, size_t max, double dist) : Bulk_quote(book, p, min, dist), max_qty(max) {}
double net_price(size_t cnt) const final override {
if (cnt > max_qty) return max_qty * (1 - discount) * price + (cnt - max_qty) * price;
else if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
virtual void debug() const final {
Bulk_quote::debug();
cout << "\tmax_qty: " << max_qty << endl;
}
private:
size_t max_qty = 0;
};
}
#endif // CP5_EX15_11_LIMIT_QUOTE_H_
15.12
当然。override意味着覆盖基类中的同名虚函数。final是防止任何在级别更低的派生类重写此虚函数。
15.13
该派生类的虚函数想要调用它覆盖的基类的虚函数版本,但是没有使用使用作用域运算符,会导致无限递归。
fixed: void print(ostream &os) {base::print(os); os << " " << i;}
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() runtime
(f) br2.print(); // derived::print() runtime
当且仅当对通过指针或引用调用虚函数时,才会在运行时解析该调用。
15.15
Disc_quote
#ifndef CP5_EX15_15_DISC_QUOTE_H_
#define CP5_EX15_15_DISC_QUOTE_H_
#include "ex15_03_Quote.h"
#include <string>
inline namespace EX15 {
using std::string;
class Disc_quote : public EX03::Quote {
public:
Disc_quote() = default;
Disc_quote(string const& b, double p, size_t q, double d) : EX03::Quote(b, p), quantity(q), discount(d){ }
virtual double net_price(size_t) const = 0;
protected:
size_t quantity = 0;
double discount = 0.0;
};
}
#endif // CP5_EX15_15_DISC_QUOTE_H_
Bulk_quote
#ifndef CP5_EX15_15_BULK_QUOTE_H_
#define CP5_EX15_15_BULK_QUOTE_H_
#include "ex15_15_Disc_quote.h"
#include <string>
inline namespace EX15 {
using std::string;
class Bulk_quote : public Disc_quote {
public:
Bulk_quote() = default;
Bulk_quote(string const& book, double price, size_t qty, double disc) : Disc_quote(book, price, qty, disc) { }
virtual double net_price(std::size_t cnt) const override {
if (cnt >= quantity) return cnt * (1 - discount) * price;
else return cnt * price;
}
};
}
#endif // CP5_EX15_15_BULK_QUOTE_H_
15.16
#ifndef CP5_EX15_16_LIMIT_QUOTE_H_
#define CP5_EX15_16_LIMIT_QUOTE_H_
#include "ex15_15_Disc_quote.h"
#include <string>
namespace EX16 {
using std::string;
using std::cout; using std::endl;
using namespace EX15;
class Limit_quote : public Disc_quote {
public:
Limit_quote() = default;
Limit_quote(string const& book, double p, size_t min, size_t max, double dist) : Disc_quote(book, p, min, dist), max_qty(max) {}
double net_price(size_t cnt) const final override {
if (cnt > max_qty) return max_qty * (1 - discount) * price + (cnt - max_qty) * price;
else if (cnt >= quantity) return cnt * (1 - discount) * price;
else return cnt * price;
}
private:
size_t max_qty = 0;
};
}
#endif // CP5_EX15_16_LIMIT_QUOTE_H_
15.17
note: because the following virtual functions are pure within 'ch15::EX15::Disc_quote':
virtual double net_price(size_t) const = 0;
15.18
Base *p = &d1; // d1 has type Pub_Derv -- legal
p = &d2; // d2 has type Priv_Derv -- illegal
p = &d3; // d3 has type Prot_Derv -- illegal
p = &dd1; // dd1 has type Derived_from_Public -- legal
p = &dd2; // dd2 has type Derived_from_Private -- illegal
p = &dd3; // dd3 has type Derived_from_Protected -- illegal
只有当D公有地继承B时,用户代码才能使用派生类向基类的转换:如果D继承B的方式是受保护的或者私有的,则用户代码不能使用该转换。
15.19
Pub_Derv d1; // legal
Priv_Derv d2; // legal
Prot_Derv d3; // legal
不论D以什么方式继承B,D的成员函数和友元都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的。
Derived_from_Public dd1; // legal
Derived_from_Private dd2; // illegal
Derived_from_Protected dd3; // legal
如果D继承B的方式是公有的或者受保护的,则D的派生类的成员和友元可以使用D向B的类型转换,反之,如果D继承B的方式是私有的,则不能使用。
15.20
#ifndef CP5_EX15_20_BASE_H_
#define CP5_EX15_20_BASE_H_
inline namespace EX20 {
class Base {
protected:
int prot_mem;
private:
char priv_mem;
};
class Pub_Derv : public Base {
void memfcn(Base &b) { b = *this; }
int f() { return prot_mem; }
};
class Priv_Derv : private Base {
void memfcn(Base &b) { b = *this; }
int f1() const { return prot_mem; }
};
class Prot_Derv : protected Base {
void memfcn(Base &b) { b = *this; }
int f2() { return prot_mem; }
};
struct Derived_from_Public : public Pub_Derv {
void memfcn(Base &b) { b = *this; }
int use_base() { return prot_mem; }
};
struct Derived_from_Private : public Priv_Derv {
// void memfcn(Base &b) { b = *this; } // error: 'Base' not accessible because 'Priv_Derv' uses 'private' to inherit from 'Base'
};
struct Derived_from_Protected : public Prot_Derv {
void memfcn(Base &b) { b = *this; }
};
}
#endif
15.21
#ifndef CP5_EX15_21_GEOMTRIC_PRIMITIVES_H_
#define CP5_EX15_21_GEOMTRIC_PRIMITIVES_H_
inline namespace EX21 {
static const float PI = 3.14159f;
class Shape {
public:
virtual const char* shape_name() = 0;
virtual void resize_by_percentage(float pct) = 0;
virtual ~Shape() {}
};
class Shape_2D : public Shape {
public:
Shape_2D() = default;
Shape_2D(float x, float y) : x_(x), y_(y) {}
virtual float area() const = 0;
virtual float diameter() const = 0;
virtual float circumference() const = 0;
virtual ~Shape_2D() override {}
protected:
float x_ = 0.f;
float y_ = 0.f;
};
class Shape_3D : public Shape {
public:
Shape_3D() = default;
Shape_3D(float x, float y, float z) : x_(x), y_(y), z_(z) {}
virtual float volume() const = 0;
virtual ~Shape_3D() override {}
protected:
float x_ = 0.f;
float y_ = 0.f;
float z_ = 0.f;
};
class Box : public Shape_3D {
public:
Box() = default;
explicit Box(float width) : half_len_x_(width * 0.5f), half_len_y_(width * 0.5f), half_len_z_(width * 0.5f) {}
Box(float center_x, float center_y, float center_z, float len_x, float len_y, float len_z) : Shape_3D(center_x, center_y, center_z),
half_len_x_(len_x * 0.5f), half_len_y_(len_y * 0.5f), half_len_z_(len_z * 0.5f) {}
inline virtual const char* shape_name() override { return "Box"; }
inline virtual void resize_by_percentage(float pct) override { half_len_x_ *= pct; half_len_y_ *= pct; half_len_z_ *= pct; }
inline float volume() const override { return half_len_x_ * half_len_y_ * half_len_z_ * 8; }
virtual ~Box() override {}
protected:
float half_len_x_ = 0.5f;
float half_len_y_ = 0.5f;
float half_len_z_ = 0.5f;
};
class Circle : public Shape_2D {
public:
Circle() = default;
explicit Circle(float radius) : radius_(radius) {}
Circle(float center_x, float center_y, float radius) : Shape_2D(center_x, center_y), radius_(radius) {}
inline virtual float area() const override { return PI * radius_ * radius_; }
inline virtual float diameter() const override { return 2 * radius_; }
inline virtual float circumference() const override { return 2 * PI * radius_; }
inline virtual const char* shape_name() override { return "Circle"; }
inline virtual void resize_by_percentage(float pct) override { radius_ *= pct; }
virtual ~Circle() override {}
protected:
float radius_ = 1.f;
};
class Sphere : public Shape_3D {
public:
Sphere() = default;
explicit Sphere(float radius) : radius_(radius) {}
Sphere(float center_x, float center_y, float center_z, float radius) : Shape_3D(center_x, center_y, center_z), radius_(radius) {}
inline virtual const char* shape_name() override { return "Sphere"; }
inline virtual void resize_by_percentage(float pct) override { radius_ *= pct; }
inline float volume() const override { return 4 * PI * radius_ * radius_ * radius_ / 3; }
virtual ~Sphere() override {}
protected:
float radius_ = 1.f;
};
class Cone : public Shape_3D {
public:
Cone() = default;
Cone(float radius, float height) : radius_(radius), height_(height) {}
Cone(float center_x, float center_y, float center_z, float radius, float height) : Shape_3D(center_x, center_y, center_z), radius_(radius), height_(height) {}
inline virtual const char* shape_name() override { return "Cone"; }
inline virtual void resize_by_percentage(float pct) override { radius_ *= pct; height_ *= pct; }
inline float volume() const override { return PI * radius_ * radius_ * height_ / 3; }
virtual ~Cone() override {}
protected:
float radius_ = 1.f;
float height_ = 1.f;
};
}
#endif // CP5_EX15_21_GEOMTRIC_PRIMITIVES_H_
15.22
shape_name()
, resize_by_percentage(float pct)
, area()
, volume()
15.23
#include <iostream>
#include <string>
#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"
class Base
{
public:
virtual int fcn(){std::cout << "Base::fcn()\n"; return 0;}
};
class D1 : public Base
{
public:
int fcn() override {std::cout << "D1::fcn()\n";return 0;}
//! ^^^--fixed to override the inherited version
virtual void f2() {std::cout << "D1::f2()\n";}
};
class D2 : public D1
{
public:
int fcn(int);
int fcn() override {std::cout << "D2::fcn()\n";return 0;}
void f2() override {std::cout << "D2::f2()\n";}
};
int main()
{
Base bobj;
D1 d1obj;
D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
//bp1->fcn(); //! virtual call, will call Base::fcn at run time
//bp2->fcn(); //! virtual call, will call D1::fcn at run time
//bp3->fcn(); //! virtual call, will call D2::fcn at run time
D1 *d1p = &d1obj; D2 *d2p = &d2obj;
//bp2->f2();
//!^^^^^^^^^^^^
//! @note You are calling virtual member functions via a pointer
//! to Base. That means that you can only call methods that exist
//! in the Base class. You cannot simply add methods to a type
//! dynamically.
//d1p->f2(); //! virtual call, will call D1::f2() at run time
//d2p->f2(); //! virtual call, will call D2::f2() at run time
return 0;
}
15.24
通常,基类需要一个虚析构函数,就可以动态分配继体系中的对象。
15.25
原因是已经定义了一个4个参数的构造函数,这使得编译器无法生成合成的默认构造函数(P236)。因此,从它派生的任何类的默认构造函数都将是被删除的(P553)。因此,必须显式定义默认构造函数,以便派生类在执行其默认构造函数时可以调用它。
15.26
Quote
#ifndef CP5_EX15_26_QUOTE_H
#define CP5_EX15_26_QUOTE_H
#include <string>
#include <iostream>
namespace EX26 {
using std::string;
using std::cout; using std::endl;
class Quote {
public:
Quote() {
cout << "Quote Constructor" << endl;
}
Quote(const string &b, double p) : bookNo(b), price(p) {
cout << "Quote Constructor taking two parameters" << endl;
}
Quote(const Quote &rhs) : bookNo(rhs.bookNo), price(rhs.price) {
cout << "Quote Copy Constructor" << endl;
}
Quote& operator=(const Quote &rhs) {
cout << "Quote Copy assignment operator" << endl;
price = rhs.price;
bookNo = rhs.bookNo;
return *this;
}
Quote(Quote &&rhs) noexcept : bookNo(std::move(rhs.bookNo)), price(std::move(rhs.price)) {
cout << "Quote Move Constructor" << endl;
}
Quote& operator=(Quote &&rhs) noexcept {
cout << "Quote Move assignment operator" << endl;
bookNo = std::move(rhs.bookNo);
price = std::move(rhs.price);
return *this;
}
virtual ~Quote() {
cout << "Quote Destructor" << endl;
}
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const { return n * price; }
private:
string bookNo;
protected:
double price = 0.0;
};
}
#endif //CP_EX15_26_QUOTE_H
Bulk_quote
#ifndef CP5_EX15_26_DISC_QUOTE_H
#define CP5_EX15_26_DISC_QUOTE_H
#include "ex15_26_Quote.h"
namespace EX26 {
class Bulk_quote : public Quote {
public:
Bulk_quote() {
cout << "Bulk_quote Constructor" << endl;
}
Bulk_quote(const string &b, double p, size_t q, double d) : Quote(b, p), min_qty(q), discount(d) {
cout << "Bulk_quote Constructor taking four paramters" << endl;
}
Bulk_quote(const Bulk_quote& rhs) : Quote(rhs), min_qty(rhs.min_qty), discount(rhs.discount) {
cout << "Bulk_quote Copy Constructor" << endl;
}
Bulk_quote& operator=(const Bulk_quote& rhs) {
cout << "Bulk_quote Copy assignment operator" << endl;
Quote::operator=(rhs);
min_qty = rhs.min_qty;
discount = rhs.discount;
return *this;
}
Bulk_quote(Bulk_quote &&rhs) noexcept : Quote(rhs), min_qty(std::move(rhs.min_qty)),
discount(std::move(rhs.discount)) {
cout << "Bulk_quote Move constructor" << endl;
}
Bulk_quote& operator=(Bulk_quote &&rhs) noexcept {
cout << "Bulk_quote Move assignment operator" << endl;
Quote::operator=(rhs);
min_qty = std::move(rhs.min_qty);
discount = std::move(rhs.discount);
return *this;
}
virtual ~Bulk_quote() {
cout << "Bulk_quote destructor" << endl;
}
virtual double net_price(size_t cnt) const override {
if (cnt >= min_qty) return cnt * (1 - discount) * price;
else return cnt * price;
}
protected:
size_t min_qty = 0;
double discount = 0.0;
};
}
#endif //CP5_EX15_26_DISC_QUOTE_H
15.27
#ifndef CP5_EX15_27_BULK_QUOTE_H
#define CP5_EX15_27_BULK_QUOTE_H
#include "ex15_15_Disc_quote.h"
inline namespace EX27 {
using std::string;
class Bulk_quote : public Disc_quote {
public:
using Disc_quote::Disc_quote;
virtual double net_price(std::size_t cnt) const override {
if (cnt >= quantity) return cnt * (1 - discount) * price;
else return cnt * price;
}
};
}
#endif // CP5_EX15_27_BULK_QUOTE_H
15.28
#include <vector>
#include <numeric>
#include "ex15_27_Bulk_quote.h"
int main()
{
std::vector<Quote> vecQuote;
Bulk_quote bulk0("0-201-82470-1", 50, 5, 0.2);
Bulk_quote bulk1("0-201-82470-1", 50, 3, 0.5);
// total price should be:
std::cout << "bulk_quote's total: " << bulk0.net_price(5) + bulk1.net_price(5) << std::endl;
vecQuote.push_back(bulk0);
vecQuote.push_back(bulk1);
double total = std::accumulate(vecQuote.cbegin(), vecQuote.cend(),0.0, [](double ret, const Quote &obj){
return ret += obj.net_price(5);
});
// total price in the vector.
std::cout << "total in the vector: " << total << std::endl;
}
bulk_quote's total: 325 total in the vector: 500
15.29
#include <vector>
#include <numeric>
#include <memory>
#include "ex15_27_Bulk_quote.h"
int main()
{
std::vector<std::shared_ptr<Quote>> vecQuote;
std::shared_ptr<Bulk_quote> spBulk0 = std::make_shared<Bulk_quote>("0-201-82470-1", 50, 5, 0.2);
std::shared_ptr<Bulk_quote> spBulk1 = std::make_shared<Bulk_quote>("0-201-82470-1", 50, 3, 0.5);
// total price should be:
std::cout << "bulk_quote's total: " << spBulk0->net_price(5) + spBulk1->net_price(5) << std::endl;
vecQuote.push_back(spBulk0);
vecQuote.push_back(spBulk1);
double total = std::accumulate(vecQuote.cbegin(), vecQuote.cend(),0.0, [](double ret, std::shared_ptr<Quote> sp){
return ret += sp->net_price(5);
});
// total price in the vector.
std::cout << "total in the vector: " << total << std::endl;
}
bulk_quote's total: 325 total in the vector: 325
当派生类对象被赋值给基类对象时,其中的派生类部分将被“切掉”,因此容器和存在继承关系的类型无法兼容。当我们希望在容器中存放具有继承关系的对象时,我们实际上存放的通常是基类的指针。与以前的方案不同的是,总价格计算采用了20%和50%的折扣。