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 "e_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