本书为Primer C++ 中文第五版
练习题笔记
(15.1)
虚函数:基类希望派生类进行覆盖的函数
(15.2)
派生类可以继承定义在基类的成员,但是派生类的函数不一定有权访问基类继承而来的成员。
派生类可以访问公有成员,不能访问私有成员。
定义受保护的成员使得派生类可以访问,而其他用户禁止访问
(15.3)
#ifndef QUOTE_H
#define QUOTE_H
#include <iostream>
using namespace std;
class Quote {
public:
Quote() = default;
Quote(const string &book, double sales_price) : bookNo(book), price(sales_price) { }
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;
};
#endif
(15.4)
派生类的声明只需要包含类名即可,若想将某个类用作基类,则该类必须已经定义
a>不可以继承自己
b>正确声明且定义
c>仅声明的话,只需要类名即可
(15.5)
class Bulk_Quote : public Quote {
public:
Bulk_Quote() = default;
Bulk_Quote(const string& book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) { }
double net_price(size_t n) const override {
if(n >= min_qty) return n*(1-discount)*price;
else return n*price;
}
private:
size_t min_qty;
double discount;
};
(15.6)
void test6() {
Quote q("bcsj", 12);
Bulk_Quote bq("pfdsj", 15, 5, 0.2);
//第七题定义的派生类
Bulk b("sgyy", 20, 0.2, 5);
cout << q.net_price(4) << endl;
cout << bq.net_price(1) << endl;
cout << bq.net_price(10) << endl;
cout << b.net_price(1) << endl;
cout << b.net_price(10) << endl;
}
(15.7)
class Bulk : public Quote {
public:
Bulk(const string& book, double pri, double dis, size_t n):
Quote(book, pri), discount(dis), max_qty(n) {
max_dis = n * (1 - dis) * pri;
}
double net_price(size_t n) const override {
if(n <= max_qty) return n*(1-discount)*price;
else return max_dis + (n-max_qty)*price;
}
private:
size_t max_qty;
double discount;
double max_dis;
};
(15.8)
静态类型,编译时总是已知的,它是变量声明时的类型或表达式生成的类型
动态类型,是变量或表达式表示的内存中的对象的类型,直到运行时才可知
如果表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致。
基类的指针或引用的静态类型可能与其动态类型不一致。
一个基类的对象可能是派生类对象的一部分,也可能不是,所以不存在从基类向派生类的自动类型转换
可以通过dynamic_cast 或 static_cast 进行类型转换
(15.9)
eg.
Bulk_Quote bulk;
Quote *itemP = &bulk; //itemP 动态类型是Bulk_Quote
(15.10)
ifstream类和istringstream都继承自istream类(cin)。
ofstream类和ostringstream都继承自ostream类(cout)。
read函数接受istream类的引用,所以发生了派生类向基类的类型转换。
(15.11)
class Quote {
public:
//...
virtual void debug() const {
cout << bookNo << " " << price << endl;
}
//...
};
class Bulk_Quote : public Quote {
public:
//...
void debug() const override {
Quote::debug();
cout << min_qty << " " << discount << endl;
}
//...
};
(15.12)
override表示改派生类的此函数为虚函数,每个派生类都需要定义
final表示函数不可被覆写,不允许该类的派生类定义
如果不允许该派生类的派生类覆写改函数,则有必要
(15.13)
base::print(ostream& os) 输出base的basename
derived::print(ostream& os) 调用base::print,然后输出derived的i
应该把print(os);改成 base::print(os);
(15.14)
a> base::print
b> derived::print
c> base::name
d> base::name
e> base::print
f> derived::print
(15.15)
class Disc_quote : public Quote {
public:
Disc_quote() = default;
Disc_quote(const string& book, double p, size_t qty, double disc):
Quote(book, p), quantity(qty), discount(disc) { }
double net_price(size_t n) const = 0;
void debug() const override {
Quote::debug();
cout << quantity << " " << discount << endl;
}
protected:
double discount;
size_t quantity;
};
class Bulk_quote : public Disc_quote {
public:
Bulk_quote() = default;
Bulk_quote(const string& book, double p, size_t qty, double disc):
Disc_quote(book, p, qty, disc) { }
double net_price(size_t n) const override {
if(n <= quantity) return n*(1-discount)*price;
else return quantity*(1-discount)*price+(n-quantity)*price;
}
};
(15.16)
void test16() {
Bulk_quote bq("pfdsj", 15, 5, 0.2);
Disc_quote& dp = bq;
bq.debug();
cout << dp.net_price(1) << endl;
cout << dp.net_price(10) << endl;
dp.debug();
Disc_quote dq;//17题错误示范
}
(15.17)
cannot declare variable ‘dq’ to be of abstract type ‘Disc_quote’
(15.18)
只有公有地继承,用户代码才能使用派生类向基类的转换。
Base *p = &d1; //合法
p = &d2; //不合法
p = &d3; //不合法
p = &dd1; //合法
p = &dd2; //不合法
p = &dd3; //不合法
(15.19)
不论什么方式继承,派生类的成员函数和友元都能使用派生类向基类的转换。
如果D继承B的方式是私有的,则D的派生类的成员和友元不能使用类型转换。
所以除了类Derived_from_Private不合法外,其他都合法
(15.20)
#include <iostream>
using namespace std;
class base {
public:
int pub = 0;
protected:
int prot = 1;
private:
int priv = 2;
};
class pub_derv : public base {
public:
void memfcn(base &b) {b = *this;}
int pubd() {
cout << "pub_derv pub: " << pub << endl;
}
void protd() {
cout << "pub_derv prot: " << prot << endl;
}
void privd() {
//cout << "pub_derv priv: " << priv << endl;
}
};
class prot_derv : protected base {
public:
void memfcn(base &b) {b = *this;}
void pubd() {
cout << "prot_derv pub: " << pub << endl;
}
void protd() {
cout << "prot_derv prot: " << prot << endl;
}
void privd() {
//cout << "prot_derv priv: " << priv << endl;
}
};
class priv_derv : private base {
public:
void memfcn(base &b) {b = *this;}
void pubd() {
cout << "priv_derv pub: " << pub << endl;
}
void protd() {
cout << "priv_derv prot: " << prot << endl;
}
void privd() {
//cout << "priv_derv priv: " << priv << endl;
}
};
class pub_pub_derv : public pub_derv {
public:
void memfcn(base &b) {b = *this;}
void pub_pub() {
cout << "pub_pub_derv pub: " << pub << endl;
}
void pub_prot() {
cout << "pub_pub_derv prot: " << prot << endl;
}
void pub_priv() {
//cout << "pub_pub_derv priv: " << priv << endl;
}
};
class pub_prot_derv : public prot_derv {
public:
void memfcn(base &b) {b = *this;}
void pub_pub() {
cout << "pub_prot_derv pub: " << pub << endl;
}
void pub_prot() {
cout << "pub_prot_derv prot: " << prot << endl;
}
void pub_priv() {
//cout << "pub_prot_derv priv: " << priv << endl;
}
};
class pub_priv_derv : public priv_derv {
public:
void memfcn(base &b) {b = *this;}
void pub_pub() {
//cout << "pub_prot_derv pub: " << pub << endl;
}
void pub_prot() {
//cout << "pub_prot_derv prot: " << prot << endl;
}
void pub_priv() {
//cout << "pub_prot_derv priv: " << priv << endl;
}
};
void test20() {
pub_derv d1;
priv_derv d2;
prot_derv d3;
pub_pub_derv dd1;
pub_priv_derv dd2;
pub_prot_derv dd3;
base *p = &d1;
p = &d2;
p = &d3;
p = &dd1;
p = &dd2;
p = &dd3;
}
int main() {
test20();
return 0;
}
18:
inherit.cpp:100:7: error: ‘base’ is an inaccessible base of ‘priv_derv’
p = &d2;
^
inherit.cpp:101:7: error: ‘base’ is an inaccessible base of ‘prot_derv’
p = &d3;
^
inherit.cpp:103:7: error: ‘base’ is an inaccessible base of ‘pub_priv_derv’
p = &dd2;
^
inherit.cpp:104:7: error: ‘base’ is an inaccessible base of ‘pub_prot_derv’
p = &dd3;
^
19:
inherit.cpp:86:17: error: within this context
void memfcn(base &b) {b = *this;}
^
inherit.cpp: In member function ‘void pub_priv_derv::memfcn(base&)’:
inherit.cpp:86:29: error: ‘base’ is an inaccessible base of ‘pub_priv_derv’
void memfcn(base &b) {b = *this;}
^
(15.21)
见21
(15.22)
#include <iostream>
#include <string>
using namespace std;
class Animals {
public:
Animals(string n): name(n) { }
virtual void speak() = 0;
protected:
string name;
};
class Dog : public Animals {
public:
Dog(string s): Animals(s) { }
void speak() override {
cout << "I'm " << name << ", and wang wang wang..." << endl;
}
};
class Cat : public Animals {
public:
Cat(string s): Animals(s) { }
void speak() override {
cout << "I'm " << name << ", and miao miao miao..." << endl;
}
};
int main() {
Dog d("xiaohei");
Cat c("tom");
Animals* a = &d;
a->speak();
a = &c;
a->speak();
return 0;
};
(15.23)
虚函数将在运行时确定使用虚函数的哪个版本,判断的依据是该指针所绑定对象的真实类型。
非虚函数不会发生动态绑定,实际调用的函数版本由指针的静态类型决定。
int fcn() override { }
bp2->fcn();将调用D1::fcn()
(15.24)
如果基类的析构函数不是虚函数,则delete一个指向派生类对象的基类指针则只会调用基类的析构函数
如果基类的析构函数是虚函数,则会先调用派生类的析构函数然后调用基类的析构函数
(15.25)
合成的Bulk_quote默认构造函数运行Disc_quote的默认构造函数,后者又运行Quote的默认构造函数
Quote的构造函数完成后,继续执行Disc_quote的构造函数,然后执行Bulk_quote的构造函数
如果去掉Disc_quote的构造函数,则无法对Bulk_quote进行默认初始化
#include <iostream>
#include <string>
using namespace std;
class Quote {
public:
Quote() { cout << "Quote()\n"; }
Quote(string s, double p): bookNo(s), price(p) { cout << "Quote(string, double)\n"; }
//copy construtor
Quote(const Quote& q): bookNo(q.bookNo), price(q.price) { cout << "Quote(const Quote&)\n"; }
//move construtor
Quote(Quote&& q) noexcept: bookNo(move(q.bookNo)), price(move(q.price))
{ cout << "Quote(Quote&&)\n"; }
//copy =
Quote& operator=(const Quote& q) {
bookNo = q.bookNo;
price = q.price;
cout << "Quote operator=(const Quote&)\n";
return *this;
}
//move =
Quote& operator=(Quote&& q) noexcept {
bookNo = move(q.bookNo);
price = move(q.price);
cout << "Quote operator=(Quote&&)\n";
return *this;
}
//destructor
virtual ~Quote() { cout << "~Quote()\n"; }
virtual void show() const { cout << bookNo << " " << price << endl; }
private:
string bookNo;
protected:
double price;
};
class Disc_quote : public Quote {
public:
Disc_quote() { cout << "Disc_quote()\n"; }
Disc_quote(string s, double p, size_t n, double d): Quote(s, p), quantity(n), discount(d)
{ cout << "Disc_quote(string, double, size_t, double)\n"; }
//copy construtor
Disc_quote(const Disc_quote& q):Quote(q), quantity(q.quantity), discount(q.discount)
{ cout << "Disc_quote(const Disc_quote&)\n"; }
//move construtor
Disc_quote(Disc_quote&& q) noexcept:Quote(move(q)), quantity(move(q.quantity)), discount(move(q.discount))
{ cout << "Disc_quote(Disc_quote&&)\n"; }
//copy =
Disc_quote& operator=(const Disc_quote& q) {
Quote::operator=(q);
quantity = q.quantity;
discount = q.discount;
cout << "Disc_quote operator=(const Disc_quote&)\n";
return *this;
}
//move =
Disc_quote& operator=(Disc_quote&& q) noexcept {
Quote::operator=(move(q));
quantity = move(q.quantity);
discount = move(q.discount);
cout << "Disc_quote operator=(Disc_quote&&)\n";
return *this;
}
//destructor
~Disc_quote() override { cout << "~Disc_quote()\n"; }
protected:
size_t quantity;
double discount;
};
class Bulk_quote : public Disc_quote {
public:
Bulk_quote() { cout << "Bulk_quote()\n"; }
Bulk_quote(string s, double p, size_t n, double d): Disc_quote(s, p, n, d)
{ cout << "Bulk_quote(string, double, size_t, double)\n"; }
//copy construtor
Bulk_quote(const Bulk_quote& q): Disc_quote(q)
{ cout << "Bulk_quote(const Bulk_quote&)\n"; }
//move construtor
Bulk_quote(Bulk_quote&& q) noexcept: Disc_quote(move(q))
{ cout << "Bulk_quote(Bulk_quote&&)\n"; }
//copy =
Bulk_quote& operator=(const Bulk_quote& q) {
Disc_quote::operator=(q);
cout << "Bulk_quote operator=(const Bulk_quote&)\n";
return *this;
}
//move =
Bulk_quote& operator=(Bulk_quote&& q) noexcept {
Disc_quote::operator=(move(q));
cout << "Bulk_quote operator=(Bulk_quote&&)\n";
return *this;
}
//destructor
~Bulk_quote() override { cout << "~Bulk_quote()\n"; }
};
int main() {
cout << "=========1========\n";
Bulk_quote bq1;
cout << "=========2========\n";
Bulk_quote bq2("tlbb", 20, 10, 5);
cout << "=========3========\n";
bq1 = move(bq2);
cout << "=========4========\n";
bq2.show();
cout << "=========5========\n";
return 0;
}
(15.27)
using Disc_quote::Disc_quote;
void test28() {
vector<Quote> basket;
basket.push_back(Quote("tlbb", 20));
basket.push_back(Bulk_quote("sdxn", 20, 10, 0.5));
cout << basket.back().net_price(20) << endl;
}
void test29() {
vector<shared_ptr<Quote>> basket;
basket.push_back(make_shared<Quote>("tlbb", 20));
basket.push_back(make_shared<Bulk_quote>("sdxn", 20, 10, 0.5));
cout << basket.back()->net_price(20) << endl;
}
class Basket {
public:
void add_item(const shared_ptr<Quote>& sale) { items.insert(sale); }
double total_receipt(ostream& os) const {
double sum = 0.0;
for(auto iter : items) {
iter->show();
sum += iter->net_price(20);
}
os << "sum: " << sum << endl;
return sum;
}
private:
static bool compare(const shared_ptr<Quote>& lhs, const shared_ptr<Quote>& rhs) {
return lhs->isbn() < rhs->isbn();
}
multiset<shared_ptr<Quote>, decltype(compare)*> items{compare};
};
void test30() {
Basket b;
b.add_item(make_shared<Quote>("tlbb", 20));
b.add_item(make_shared<Bulk_quote>("sdxn", 20, 10, 0.5));
b.total_receipt(cout);
}
(15.31)
a> WordQuery*3, OrQuery*1, AndQuery*1, NotQuery*1
b> WordQuery*3, OrQuery*1, AndQuery*1, NotQuery*1
c> WordQuery*4, AndQuery*2, OrQuery*1
(15.32)
拷贝:
调用合成的拷贝构造函数。在本例中,数据成员是一个共享指针,所以在拷贝时,共享指针指向相同的地址并且使用计数+1。
移动:
调用合成的移动构造函数。在本例中,共享指针指向原始共享指针指向的地址。移动操作后,新对象中共享指针的使用计数为1,原始对象的指针变成了nullptr。
赋值:
调用合成的赋值构造函数,和拷贝构造函数类似。
销毁:
调用合成析构函数。使用次数-1。如果计数变为零,将删除智能指针所指向的资源。
(15.33)
Query_base是一个抽象基类,不允许直接声明其对象。
因为这后面的代码太长了,所以重新写了一篇点我
(15.34)
Query q = Query("fiery") & Query("bird") | Query("wind");
a>
WordQuery::WordQuery(wind)
Query::Query(const std::string& s) where s=wind
WordQuery::WordQuery(bird)
Query::Query(const std::string& s) where s=bird
WordQuery::WordQuery(fiery)
Query::Query(const std::string& s) where s=fiery
BinaryQuery::BinaryQuery() where s=&
AndQuery::AndQuery()
Query::Query(std::shared_ptr<Query_base> query)
BinaryQuery::BinaryQuery() where s=|
OrQuery::OrQuery
Query::Query(std::shared_ptr<Query_base> query)
b>
Query::rep()
BinaryQuery::rep()
Query::rep()
WordQuery::rep()
Query::rep()
BinaryQuery::rep()
Query::rep()
WordQuery::rep()
Query::rep()
WordQuery::rep()
c>
Query::eval()
OrQuery::eval()
Query::eval()
WordQuery::eval()
Query::eval()
AndQuery::eval()
Query::eval()
WordQuery::eval()
Query::eval()
WordQuery::eval()
BinaryQuery::rep()
Query::rep()
WordQuery::rep()
Query::rep()
WordQuery::rep()
BinaryQuery::rep()
Query::rep()
WordQuery::rep()
Query::rep()
BinaryQuery::rep()
Query::rep()
WordQuery::rep()
Query::rep()
WordQuery::rep()
(15.35)
(15.36)
(15.37)
(15.38)
1>不合法,BinaryQuery是抽象类
2>不合法,&返回Query类,AndQuery不能转换到Query类
3>不合法,同上
(15.39)
(15.40)
不会rhs空集则返回lhs的结果,lhs空集则返回rhs的结果,两个都是空集则返回空结果
(15.41)
(15.42)