Contents
Chapter 15 Object-Oriented Programming
Quote类
Quote.h
#ifndef MY_QUOTE_H
#define MY_QUOTE_H
#include<string>
#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; };
// copy control
Quote(const Quote& rhs) : bookNo(rhs.bookNo), price(rhs.price) { };
Quote(Quote&&) = default;
Quote& operator=(const Quote& rhs) { bookNo = rhs.bookNo; price = rhs.price; return *this; };
Quote& operator=(Quote&&) = default;
virtual double net_price(std::size_t n) const { return n * price; };
//virtual void debug() const { cout << "Quote bookNo = " << bookNo << ", price = "<< price << endl; };
virtual Quote* clone() const& { return new Quote(*this); }; //获得自身对象在动态内存的一个拷贝
virtual Quote* clone()&& { return new Quote(std::move(*this)); }; //把自身对象移动到动态内存
virtual ~Quote() = default;
private:
std::string bookNo;
protected:
double price = 0.0;
};
//非成员接口函数
double print_total(ostream&, const Quote&, size_t);
class Disc_quote : public Quote
{
public:
Disc_quote() = default;
Disc_quote(const std::string& book, double sales_price, std::size_t q, double d) : Quote(book, sales_price), min_qty(q), discount(d) {};
double net_price(std::size_t) const override = 0;
protected:
std::size_t min_qty = 0;
double discount = 0.0;
};
class Bulk_quote : public Disc_quote
{
public:
Bulk_quote() = default;
// Bulk_quote(const std::string& book, double sales_price, std::size_t q, double d) :Disc_quote(book, sales_price, q, d) {};
using Disc_quote::Disc_quote; // 与上面的定义相同
double net_price(std::size_t n) const override;
//void debug() const override { cout << "Bulk_quote min_qty = " << min_qty << ", discount = " << discount << endl; };
virtual Quote* clone() const& override { return new Bulk_quote(*this); };
virtual Quote* clone() && override { return new Bulk_quote(std::move(*this)); };
// copy control
Bulk_quote(const Bulk_quote& rhs) : Disc_quote(rhs) {};
Bulk_quote(Bulk_quote&&) = default;
Bulk_quote& operator=(const Bulk_quote& rhs) { (*this).Disc_quote::operator=(rhs); return *this;};
Bulk_quote& operator=(Bulk_quote&&) = default;
};
class limited_quote : public Disc_quote
{
public:
limited_quote() = default;
limited_quote(const std::string& book, double sales_price, std::size_t q, double d) :Disc_quote(book, sales_price, q, d) {};
double net_price(std::size_t n) const override;
//void debug() const override { cout << "limited_quote min_qty = " << min_qty << ", discount = " << discount << endl; }
};
#endif
Quote.cpp
#include"Quote.h"
double Bulk_quote::net_price(std::size_t cnt) const
{
if (cnt >= min_qty)
return cnt * (1 - discount) * price;
else
return cnt * price;
}
double limited_quote::net_price(std::size_t cnt) const
{
if (cnt <= min_qty)
return cnt * (1 - discount) * price;
else
return min_qty * (1 - discount) * price + (cnt - min_qty) * price;
}
double print_total(ostream& os, const Quote& item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sole: " << n << "total due: " << ret << endl;
return ret;
}
Basket类
Basket.h
#include<memory>
#include<set>
#include<iostream>
#include"Quote.h"
using namespace std;
class Basket
{
public:
//使用默认构造函数和拷贝控制成员
void add_item(const Quote& sale) { items.insert(shared_ptr<Quote>(sale.clone())); };
void add_item(Quote&& sale) { items.insert(shared_ptr<Quote>(std::move(sale).clone())); };
double total_receipt(ostream&) const;
private:
static bool compare(const shared_ptr<Quote> & lhs, const shared_ptr<Quote>& rhs)
{
return lhs->isbn() < rhs->isbn();
}
//一个multiset,按照compare规定的方法排序
multiset<shared_ptr<Quote>, decltype(compare)*> items{ compare };
};
Basket.cpp
#include"Basket.h"
double Basket::total_receipt(ostream& os) const
{
double sum = 0.0;
for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter))
sum += print_total(os, **iter, items.count(*iter));
os << "Total Sale: " << sum << endl;
return sum;
}
TextQuery类
TextQuery.h
#include<vector>
#include<string>
#include<set>
#include<map>
#include<fstream>
#include<memory>
using namespace std;
class QueryResult;
class TextQuery
{
friend class QueryResult;
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream&);
QueryResult query(const string& word) const;
private:
shared_ptr<vector<string>> file;
map<string, shared_ptr<set<line_no>>> wm;
};
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
using line_no = vector<string>::size_type;
using line_it = set<line_no>::const_iterator;
QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f) : sought(s), lines(p), file(f) {};
line_it begin() const { return lines->begin(); };
line_it end() const { return lines->end(); };
shared_ptr<vector<string>> get_file() { return file; };
private:
string sought;
shared_ptr<set<line_no>> lines;
shared_ptr<vector<string>> file;
};
class Query_base
{
friend class Query;
protected:
using line_no = TextQuery::line_no;
virtual ~Query_base() = default;
private:
//使用给定的TextQuery对象查找与之匹配的行
virtual QueryResult eval(const TextQuery&) const = 0;
//返回查询的string表示形式
virtual string rep() const = 0;
};
class Query
{
friend Query operator~(const Query&);
friend Query operator|(const Query&, const Query&);
friend Query operator&(const Query&, const Query&);
public:
//Query接受string类型的构造函数
Query(const string&);
QueryResult eval(const TextQuery& t) const { return q->eval(t); };
string rep() const { return q->rep(); };
private:
//Query接受不同派生类型的Query_base对象的构造函数
Query(shared_ptr<Query_base> query) : q(query) {};
//被查询对象的指针
shared_ptr<Query_base> q;
};
//ostream& operator<<(ostream& os, const Query& query)
//{
// return os << query.rep();
//}
inline ostream& operator<<(ostream& os, const Query& query) {
// Query::rep makes a virtual call through its Query_base pointer to rep()
return os << query.rep();
}
class WordQuery : public Query_base
{
friend class Query;
WordQuery(const string& s) : query_word(s) {};
QueryResult eval(const TextQuery& t) const { return t.query(query_word); };
string rep() const { return query_word; };
//要查询的单词
string query_word;
};
//Query接受string的构造函数
inline Query::Query(const string& s) :q(new WordQuery(s)) {};
class NotQuery : public Query_base
{
friend Query operator~(const Query&);
NotQuery(const Query& q) : query(q) {};
string rep() const { return "~(" + query.rep() + ")"; };
QueryResult eval(const TextQuery&) const;
Query query;
};
//Query接受NotQuery的构造函数
inline Query operator~(const Query& operand)
{
//返回一个shared_ptr<Query_base>指针,相当于使用Query(shared_ptr<Query_base> query)隐式构建了Query对象
return shared_ptr<Query_base>(new NotQuery(operand));
}
class BinaryQuery :public Query_base
{
protected:
BinaryQuery(const Query& l, const Query& r, string s) :lhs(l), rhs(r), opSym(s) {};
string rep() const { return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")"; };
Query lhs, rhs;
string opSym; //运算符的名字
};
class AndQuery : public BinaryQuery
{
friend Query operator&(const Query&, const Query&);
AndQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "&") {};
QueryResult eval(const TextQuery&) const;
};
inline Query operator&(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
class OrQuery : public BinaryQuery
{
friend Query operator|(const Query&, const Query&);
OrQuery(const Query& left, const Query right) :BinaryQuery(left, right, "|") {};
QueryResult eval(const TextQuery&) const;
};
inline Query operator|(const Query& lhs, const Query& rhs)
{
return shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
TextQuery.cpp
#include"TextQuery.h"
#include<sstream>
#include<algorithm>
#include<iostream>
TextQuery::TextQuery(ifstream& is) : file(new vector<string>)
{
string text;
while (getline(is, text))
{
file->push_back(text);
size_t n = file->size() - 1;
istringstream line(text);
string word;
while (line >> word)
{
shared_ptr<set<line_no>>& lines = wm[word]; //lines是指向set的智能指针
if (!lines) //第一次遇到word时需要给lines分配一个新的内存空间
lines.reset(new set<line_no>);
lines->insert(n);
}
}
}
QueryResult TextQuery::query(const string& sought) const
{
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if (loc == wm.end())
return QueryResult(sought, nodata, file); //未找到
else
return QueryResult(sought, loc->second, file);
}
ostream& print(ostream& os, const QueryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " " << ((qr.lines->size()) > 1 ? "times" : "time") << endl;
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
return os;
}
QueryResult OrQuery::eval(const TextQuery& text) const
{
//返回right和left的QueryResult
auto right = rhs.eval(text), left = lhs.eval(text);
//将左侧运算结果的行号拷贝到set中
auto ret_lines = make_shared<set<line_no>>(left.begin(), left.end());
//插入右侧运算对象所得的行号
ret_lines->insert(right.begin(), right.end());
//返回一个新的QueryResult,用于表示lhs和rhs的并
return QueryResult(rep(), ret_lines, left.get_file());
}
QueryResult AndQuery::eval(const TextQuery& text) const
{
auto left = lhs.eval(text), right = rhs.eval(text);
auto ret_lines = make_shared<set<line_no>>();
set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));
return QueryResult(rep(), ret_lines, left.get_file());
}
QueryResult NotQuery::eval(const TextQuery& text) const
{
auto result = query.eval(text);
auto ret_lines = make_shared<set<line_no>>();
auto beg = result.begin(), end = result.end();
auto sz = result.get_file()->size();
for (size_t n = 0; n != sz; ++n)
{
if (beg == end || *beg != n)
ret_lines->insert(n);
else if (beg != end)
++beg;
}
return QueryResult(rep(), ret_lines, result.get_file());
}
Homework
Test 15.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() << " # sole: " << n << "total due: " << ret << endl;
return ret;
}
Test 15.5
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 sales_price, std::size_t q, double d) : Quote(book, sales_price), min_qty(q), discount(d) {};
double net_price(std::size_t n) 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;
}
Test 15.6
int main()
{
Quote q1("primer", 66.66);
Bulk_quote q2("engine", 99.99, 2, 0.2);
print_total(cout, q1, 4);
print_total(cout, q2, 3);
return 0;
}
Test 15.7
class limited_quote : public Quote
{
public:
limited_quote() = default;
limited_quote(const std::string& book, double sales_price, std::size_t q, double d) : Quote(book, sales_price), max_qty(q), discount(d) {};
double net_price(std::size_t n) const override;
private:
std::size_t max_qty = 0;
double discount = 0.0;
};
double limited_quote::net_price(std::size_t cnt) const
{
if (cnt <= max_qty)
return cnt * (1 - discount) * price;
else
return max_qty * (1 - discount) * price + (cnt - max_qty) * price;
}
int main()
{
Quote q1("primer", 66.66);
Bulk_quote q2("engine", 66.66, 2, 0.2);
limited_quote q3("render", 66.66, 3, 0.2);
print_total(cout, q1, 4);
print_total(cout, q2, 4);
print_total(cout, q3, 4);
return 0;
}
Test 15.11
class Quote
{
public:
virtual void debug() const { cout << "Quote bookNo = " << bookNo << ", price = "<< price << endl; };
private:
std::string bookNo;
protected:
double price = 0.0;
};
class Bulk_quote : public Disc_quote
{
public:
void debug() const override{ cout << "Bulk_quote min_qty = " << min_qty <<", discount = " << discount << endl; }
};
class limited_quote : public Disc_quote
{
public:
void debug() const override { cout << "limited_quote min_qty = " << min_qty << ", discount = " << discount << endl; }
};
Test 15.15 & 15.16
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() const { cout << "Quote bookNo = " << bookNo << ", price = "<< price << endl; };
virtual ~Quote() = default;
private:
std::string bookNo;
protected:
double price = 0.0;
};
class Disc_quote : public Quote
{
public:
Disc_quote() = default;
Disc_quote(const std::string& book, double sales_price, std::size_t q, double d) : Quote(book, sales_price), min_qty(q), discount(d) {};
double net_price(std::size_t) const override = 0;
protected:
std::size_t min_qty = 0;
double discount = 0.0;
};
class Bulk_quote : public Disc_quote
{
public:
Bulk_quote() = default;
Bulk_quote(const std::string& book, double sales_price, std::size_t q, double d) :Disc_quote(book, sales_price, q, d) {};
double net_price(std::size_t n) const override;
void debug() const override{ cout << "Bulk_quote min_qty = " << min_qty <<", discount = " << discount << endl; }
};
class limited_quote : public Disc_quote
{
public:
limited_quote() = default;
limited_quote(const std::string& book, double sales_price, std::size_t q, double d) :Disc_quote(book, sales_price, q, d) {};
double net_price(std::size_t n) const override;
void debug() const override { cout << "limited_quote min_qty = " << min_qty << ", discount = " << discount << endl; }
};
Test 15.17
不允许使用抽象类类型的对象
Test 15.19
class Base
{
public:
void pub_mem();
protected:
int prot_mem;
private:
char priv_mem;
};
struct Pub_Derv : public Base
{
void memfunc(Base& b) { b = *this; };
};
struct Priv_Derv : private Base
{
void memfunc(Base& b) { b = *this; };
};
struct Prot_Derv : protected Base
{
void memfunc(Base& b) { b = *this; };
};
struct Derived_from_Public : public Pub_Derv
{
void memfunc(Base& b) { b = *this; };
};
struct Derived_from_Private : public Priv_Derv
{
void memfunc(Base& b) { b = *this; };
};
struct Derived_from_Protected : public Prot_Derv
{
void memfunc(Base& b) { b = *this; };
};
int main()
{
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public d4;
Derived_from_Private d5;
Derived_from_Protected d6;
Base* p = &d1;
p = &d2;
p = &d3;
p = &d4;
p = &d5;
p = &d6
return 0;
}
Test 15.21
考察数据抽象能力,Shape类参考自第 15 章 (houhaibushihai.me)
tatic 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; // 周长
~Shape_2D() override { }
private:
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; // 体积
~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) { }
const char* shape_name() override { return "Box"; }
void resize_by_percentage(float pct) override {
half_len_x_ *= pct;
half_len_y_ *= pct;
half_len_z_ *= pct;
}
float volume() const override {
return half_len_x_ * half_len_y_ * half_len_z_ * 8;
}
~Box() override { }
private:
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) { }
float area() const override {
return PI * radius_ * radius_;
}
float diameter() const override {
return 2 * radius_;
}
float circumference() const override {
return 2 * PI * radius_;
}
const char* shape_name() override { return "Circle"; }
void resize_by_percentage(float pct) override { radius_ *= pct; }
~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) { }
const char* shape_name() override { return "Sphere"; }
void resize_by_percentage(float pct) override { radius_ *= pct; }
float volume() const override {
return 4 * PI * radius_ * radius_ * radius_ / 3;
}
~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) { }
const char* shape_name() override { return "Cone"; }
void resize_by_percentage(float pct) override {
radius_ *= pct;
height_ *= pct;
}
float volume() const override {
return PI * radius_ * radius_ * height_ / 3;
}
~Cone() override { }
protected:
float radius_ = 1.f; // 圆锥体底面圆半径
float height_ = 1.f; // 圆锥体高
};
Test 15.26
using namespace std;
class Quote
{
public:
// copy control
Quote(const Quote& rhs) : bookNo(rhs.bookNo), price(rhs.price) { cout << "do Quote copy" << endl; };
Quote(Quote&&) = default;
Quote& operator=(const Quote& rhs) { bookNo = rhs.bookNo; price = rhs.price; cout << "do Quote '='" << endl; return *this; };
Quote& operator=(Quote&&) = default;
private:
std::string bookNo;
protected:
double price = 0.0;
};
class Disc_quote : public Quote
{
//.....
};
class Bulk_quote : public Disc_quote
{
public:
// copy control
Bulk_quote(const Bulk_quote& rhs) : Disc_quote(rhs) {cout << "do Bulk_quote copy" << endl;};
Bulk_quote(Bulk_quote&&) = default;
Bulk_quote& operator=(const Bulk_quote& rhs) { (*this).Disc_quote::operator=(rhs); cout << "do Bulk_quote '='" << endl; return *this;};
Bulk_quote& operator=(Bulk_quote&&) = default;
};
Test 15.27
class Bulk_quote : public Disc_quote
{
public:
Bulk_quote() = default;
// Bulk_quote(const std::string& book, double sales_price, std::size_t q, double d) :Disc_quote(book, sales_price, q, d) {};
using Disc_quote::Disc_quote; // 与上面的定义相同
};
Test 15.28
int main()
{
vector<Quote> vec;
vec.push_back(Bulk_quote("book1", 30, 2, 0.2));
vec.push_back(Bulk_quote("book2", 40, 2, 0.2));
vec.push_back(Bulk_quote("book3", 50, 2, 0.2));
double sum = 0;
for (auto& i: vec)
sum += i.net_price(4);
cout << sum << endl;
return 0;
}
这个程序不符合设计意图,添加进vec的Bulk_quote对象被强制转化成了Quote对象,派生类部分(折扣相关的成员)被忽略掉
Test 15.29
int main()
{
vector<shared_ptr<Quote>> vec;
vec.push_back(make_shared<Bulk_quote>("book1", 30, 2, 0.2));
vec.push_back(make_shared<Bulk_quote>("book2", 40, 2, 0.2));
vec.push_back(make_shared<Bulk_quote>("book3", 50, 2, 0.2));
double sum = 0;
for (auto& i: vec)
sum += i->net_price(4);
cout << sum << endl;
return 0;
}
Test 15.30
Quote.h 更新
class Quote
{
virtual Quote* clone() const& { return new Quote(*this); }; //获得自身对象在动态内存的一个拷贝
virtual Quote* clone()&& { return new Quote(std::move(*this)); }; //把自身对象移动到动态内存
virtual ~Quote() = default;
};
//非成员接口函数
double print_total(ostream&, const Quote&, size_t);
class Bulk_quote : public Disc_quote
{
public:
virtual Quote* clone() const& override { return new Bulk_quote(*this); };
virtual Quote* clone() && override { return new Bulk_quote(std::move(*this)); };
};
Basket.h
class Basket
{
public:
//使用默认构造函数和拷贝控制成员
void add_item(const Quote& sale) { items.insert(shared_ptr<Quote>(sale.clone())); };
void add_item(Quote&& sale) { items.insert(shared_ptr<Quote>(std::move(sale).clone())); };
double total_receipt(ostream&) const;
private:
static bool compare(const shared_ptr<Quote> & lhs, const shared_ptr<Quote>& rhs)
{
return lhs->isbn() < rhs->isbn();
}
//一个multiset,按照compare规定的方法排序
multiset<shared_ptr<Quote>, decltype(compare)*> items{ compare };
};
Basket.cpp
double Basket::total_receipt(ostream& os) const
{
double sum = 0.0;
for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter))
sum += print_total(os, **iter, items.count(*iter));
os << "Total Sale: " << sum << endl;
return sum;
}
main.cpp
int main()
{
Basket basket;
Bulk_quote b1("book1", 30, 2, 0.2);
Bulk_quote b2("book2", 40, 4, 0.2);
Bulk_quote b3("book3", 50, 1, 0.2);
basket.add_item(b1);
basket.add_item(b1);
basket.add_item(b1);
basket.add_item(b2);
basket.add_item(b3);
basket.add_item(b2);
basket.total_receipt(cout);
return 0;
}
Test 15.31
(a): WordQuery -> NotQuery -> AndQuery -> OrQuery
(b): WordQuery -> NotQuery -> AndQuery -> OrQuery (same as the previous one)
(c): WordQuery -> AndQuery -> OrQuery