第十五章 面向对象程序设计

15.1

虚函数:基类的成员函数,并在其前面添加关键字virtual,此类函数是基类希望其派生类进行覆盖的函数

15.2

protected:对应受保护成员,派生类可以访问该成员,但其他用户则禁止访问该成员

15.3

 1 class Quote {
 2 public:
 3     Quote() = default;
 4     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) {}
 5     string isbn() const { return bookNo; }
 6     virtual double net_price(size_t n) const { return n * price; }
 7     virtual ~Quote() = default;
 8 private:
 9     string bookNo;
10 protected:
11     double price = 0.0; 
12 };
13 
14 double print_total(ostream &os, const Quote &item, size_t n)
15 {
16     double ret = item.net_price(n);
17     os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
18     return ret; 
19 }
View Code

15.4

(a):错误,不可以继承自己

(b):正确

(c):错误,派生类的声明不需要包含它的派生列表

15.5

class Bulk_quote : public Quote {
public:
	Bulk_quote() = default;
	Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) {}
	double net_price(size_t n) const override;
private:
	size_t min_qty = 0;
	double discount = 0.0;
};

double Bulk_quote::net_price(size_t n) const
{
	if (n >= min_qty)
		return n * (1 - discount) * price;
	else
		return n * price;
}

15.6

 1 #include <iostream>
 2 #include <string>
 3  
 4 using namespace std;
 5 
 6 class Quote {
 7 public:
 8     Quote() = default;
 9     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) {}
10     string isbn() const { return bookNo; }
11     virtual double net_price(size_t n) const { return n * price; }
12     virtual ~Quote() = default;
13 private:
14     string bookNo;
15 protected:
16     double price = 0.0; 
17 };
18 
19 class Bulk_quote : public Quote {
20 public:
21     Bulk_quote() = default;
22     Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) {}
23     double net_price(size_t n) const override;
24 private:
25     size_t min_qty = 0;
26     double discount = 0.0;
27 };
28 
29 double Bulk_quote::net_price(size_t n) const
30 {
31     if (n >= min_qty)
32         return n * (1 - discount) * price;
33     else
34         return n * price;
35 }
36 
37 double print_total(ostream &os, const Quote &item, size_t n)
38 {
39     double ret = item.net_price(n);
40     os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
41     return ret; 
42 }
43 
44 
45 int main()
46 {
47     Quote book("3-298-15-2", 37.0);
48     Bulk_quote book2("3-298-15-2", 37.0, 5, 0.2);
49     print_total(cout, book2, 1);
50     print_total(cout, book2, 5);
51     print_total(cout, book, 5);
52     return 0; 
53 }
View Code

15.7

 1 class Limited_quote : public Quote {  
 2 public:  
 3     double net_price(size_t cnt) const override; 
 4 private:  
 5     size_t max_qty = 0;  
 6     double discount = 0.0;  
 7 };  
 8 
 9 double Limited_quote::net_price(size_t cnt) const 
10 {  
11     if (cnt <= max_qty)  
12         return cnt * (1- discount) * price;  
13     else  
14         return max_qty * (1-discount) * price + (cnt - max_qty) * price;  
15 } 
View Code

15.8

知识点:存在继承关系的类型、(变量或)表达式的静态类型

静态类型:表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型

动态类型:动态类型直到运行时才可知,(变量或)表达式表示的内存中的对象的类型

如当print_total调用net_price时:double ret = item.net_price(n);,我们知道item的静态类型是Quote&,它的动态类型则依赖于item绑定的实参(即动态类型知道运行时调用print_total才知道),若我们传递一个Bulk_quote对象给print_total,则item的静态类型将与它的动态类型不一致(此时item的静态类型是Quote&,而相应的动态类型是Bulk_quote)

15.9

基类的引用(或指针)的静态类型可能与其动态类型不一致

Bulk_quote book;

Quote &item = book;

Quote *item1 = &book;

print_total(cout, book, 2);

15.10

ifstream in("data.txt");

read(istream &is, Sales_data &item)  ====》 read(cin, total)  ====》 read(in, total)

因为iostream是fstream的基类,且参数为基类的引用,故我们可以使用派生类的对象作为实参。

15.11

 1 #include <iostream>
 2 #include <string>
 3  
 4 using namespace std;
 5 
 6 class Quote {
 7 public:
 8     Quote() = default;
 9     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) {}
10     string isbn() const { return bookNo; }
11     virtual void debug() const { cout << "bookNo	" << "price	"; }
12     virtual ~Quote() = default;
13 private:
14     string bookNo;
15 protected:
16     double price = 0.0; 
17 };
18 
19 class Bulk_quote : public Quote {
20 public:
21     Bulk_quote() = default;
22     Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) {}
23     void debug() const override { Quote::debug();    cout << "min_qty	" << "discount	"; }
24 private:
25     size_t min_qty = 0;
26     double discount = 0.0;
27 };
28 
29 int main()
30 {
31     Quote book("3-298-15-2", 37.0);
32     Bulk_quote book2("3-298-15-2", 37.0, 5, 0.2);
33     book.debug();
34     cout << endl;
35     book2.debug();
36     return 0; 
37 }
View Code

15.12

有必要,因为它们两个的意思不包含也不互斥(两不相干),加上它们可以使成员函数的意义更明确。

15.13

基类base中的print函数:打印数据成员basename的值

派生类derived中的print函数:函数体中的print(os);本意是调用基类base的print函数,但在运行时该调用被解析为对自身的调用,从而导致无限递归

解决方法是:强迫其执行虚函数的某个特定版本,此题中我们强制其调用基类中的print函数(base::print(os);)

15.14

(a):调用基类版本的print()函数

(b):调用派生类版本的print()函数

(c):调用基类的name()函数

(d):调用派生类中基类部分的name()函数

(e):调用基类版本

(f):调用派生类版本

15.15

 1 class Quote {
 2 public:
 3     Quote() = default;
 4     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) {}
 5     string isbn() const { return bookNo; }
 6     virtual double net_price(size_t) const; 
 7     virtual ~Quote() = default;
 8 private:
 9     string bookNo;
10 protected:
11     double price = 0.0; 
12 };
13 
14 //抽象基类 
15 class Disc_quote : public Quote {
16 public:
17     Disc_quote() = default;
18     Disc_quote(const string &book, double price, size_t qty, double disc): Quote(book, price), quantity(qty), discount(disc) { }
19     double net_price(size_t) const = 0;        //纯虚函数 
20 protected:
21     size_t quantity = 0;
22     double discount = 0.0;
23 };
24 
25 class Bulk_quote : public Disc_quote {
26 public:
27     Bulk_quote() = default;
28     Bulk_quote(const string &book, double price, size_t qty, double disc): Disc_quote(book, price, qty, disc) { }
29     double net_price(size_t) const override;
30 };
View Code

15.16

1 class Limited_quote : public Disc_quote {  
2 public:  
3     Limited_quote() = default;
4     Limited_quote(const string &book, double price, size_t qty, double disc, size_t mqty): Disc_quote(book, price, qty, disc), max_qty(mqty) { }
5     double net_price(size_t cnt) const override;
6 private:  
7     size_t max_qty = 0;          //超过max_qty本的部分为原价出售 
8 }; 
View Code

15.17

错误信息:

[Error] cannot declare variable 'book' to be of abstract type 'Disc_quote'

[Note] because the following virtual functions are pure within 'Disc_quote':

[Note] virtual double Disc_quote::net_price(size_t) const

15.18

只有d1和dd1才能够赋值。

这是因为:只有当派生类公有地继承基类时,用户代码才能使用派生类向基类的转换;也就是说,如果派生类继承基类的方式是受保护的或者私有的,则用户代码不能使用该转换。

在题中,只有d1和dd1类是公有地继承基类,故只有它们才能完成向基类的转换。

15.19

我认为都不合法,因为b中的private成员我们在派生类中不可以访问。

不合法:Derived_from_private: public Priv_derv

纠正我的想法:基类的private成员是继承到派生类的,只是不能访问而已。

15.20

 1 class Base {
 2 public:
 3     void pub_mem()
 4     {
 5         cout << "yes" << endl;
 6     }
 7 protected:
 8     int prot_mem = 1;
 9 private:
10     int priv_mem = 0;
11 };
12 
13 //公有继承 
14 class Pub_derv : public Base {
15     void memfcn(Base &b){    b = *this;    } 
16 };
17 
18 //私有继承 
19 class Priv_derv : private Base {
20     void memfcn(Base &b){    b = *this;    } 
21 };
22 
23 class Derived_from_public : public Pub_derv {
24     void memfcn(Base &b){    b = *this;    } 
25 };
26 
27 class Derived_from_private : public Priv_derv {
28     void memfcn(Base &b){    b = *this;    }         //报错 
29 };
View Code

15.23

修改如下:

class D1 : public Base {
public:
	int fcn() override;
};

此时执行bp2->fcn();,发现在运行时调用D1::fcn

15.24

需要虚析构函数的类:基类通常应该定义一个虚析构函数,这样我们才能动态分配继承体系中的对象(特别是当一个动态分配的对象的指针指向继承体系中的某个类型,该指针的静态类型与被删除对象的动态类型不符时,如我们要删除一个指向派生类对象的基类指针时)

虚析构函数应该执行的操作:执行指针指向的类型的析构函数

15.25

因为如果Disc_quote没有定义默认构造函数,那么编译器将无法构造派生类(即Bulk_quote)对象的基类(即Disc_quote)部分。

去掉的话,将无法构造Disc_quote对象,因为其基类部分无法构造。

15.26

 1 #include <iostream>
 2 #include <string>
 3   
 4 using namespace std;
 5 
 6 class Quote {
 7 public:
 8     Quote() = default;
 9     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { cout << "基类带参构造函数
"; }
10     Quote(const Quote &rhs): bookNo(rhs.bookNo), price(rhs.price) { cout << "基类拷贝构造函数
"; }
11     Quote(Quote &&rhs): bookNo(move(rhs.bookNo)), price(move(rhs.price)) { cout << "基类移动构造函数
"; }
12     Quote &operator=(const Quote &rhs)
13     {
14         bookNo = rhs.bookNo;
15         price = rhs.price;
16         cout << "基类拷贝赋值运算符
";
17         return *this;
18     }
19     Quote &operator=(Quote &&rhs)
20     {
21         bookNo = move(rhs.bookNo);
22         price = move(rhs.price);
23         cout << "基类移动赋值运算符
";
24         return *this;
25     }
26     string isbn() const { return bookNo; }
27 private:
28     string bookNo;
29 protected:
30     double price = 0.0; 
31 };
32 
33 class Bulk_quote : public Quote {
34 public:
35     Bulk_quote() = default;
36     Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) { cout << "派生类带参构造函数
"; }
37     Bulk_quote(const Bulk_quote &rhs): Quote(rhs), min_qty(rhs.min_qty), discount(rhs.discount) { cout << "派生类拷贝构造函数
"; }
38     Bulk_quote(Bulk_quote &&rhs): Quote(move(rhs)), min_qty(move(rhs.min_qty)), discount(move(rhs.discount)) { cout << "派生类移动构造函数
"; }
39     Bulk_quote &operator=(const Bulk_quote &rhs)
40     {
41         Quote::operator=(rhs);
42         min_qty = rhs.min_qty;
43         discount = rhs.discount;
44         cout << "派生类拷贝赋值运算符
";
45         return *this;
46     }
47     Bulk_quote &operator=(Bulk_quote &&rhs)
48     {
49         Quote::operator=(move(rhs));
50         min_qty = move(rhs.min_qty);
51         discount = move(rhs.discount);
52         cout << "派生类移动赋值运算符
";
53         return *this;
54     }
55 private:
56     size_t min_qty = 0;
57     double discount = 0.0;
58 };
59 
60 int main()
61 {
62     Quote q;                            //基类默认构造函数 
63     Quote q1("2-318-19-5", 20.0);        //基类带参构造函数 
64     Quote q2(q1);                        //基类拷贝构造函数
65     Quote q3(move(q1));                    //基类移动构造函数
66     q = q1;                                //基类拷贝赋值运算符 
67     q = move(q1);                         //基类移动赋值运算符
68     Bulk_quote b;                        //基类默认构造函数+派生类默认构造函数 
69     Bulk_quote b1("2-318-19-6", 30.0, 5, 0.2);    //基类带参构造函数+派生类带参构造函数
70     Bulk_quote b2(b1);                    //基类拷贝构造函数+派生类拷贝构造函数 
71     Bulk_quote b3(move(b1));            //基类移动构造函数+派生类移动构造函数 
72     b = b1;                                //基类拷贝赋值运算符+派生类拷贝赋值运算符 
73     b = move(b1);                         //基类移动赋值运算符+派生类移动赋值运算符 
74     return 0;
75 }
View Code

15.27

 1 #include <iostream>
 2 #include <string>
 3   
 4 using namespace std;
 5 
 6 class Quote {
 7 public:
 8     Quote() = default;
 9     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { cout << "基类带参构造函数
"; }
10     string isbn() const { return bookNo; }
11 private:
12     string bookNo;
13 protected:
14     double price = 0.0; 
15 };
16 
17 class Bulk_quote : public Quote {
18 public:
19     Bulk_quote() = default;    
20     using Quote::Quote;            //不可继承默认、移动、拷贝构造函数 
21     Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) { cout << "派生类带参构造函数
"; }
22 private:
23     size_t min_qty = 0;
24     double discount = 0.0;
25 };
26 
27 int main()
28 {
29     Bulk_quote b1("2-318-19-6", 30.0);        //基类带参构造函数
30     return 0;
31 }
View Code

15.28

 1 int main()
 2 {
 3     double sum = 0.0;
 4     vector<Quote> basket;
 5     Bulk_quote b("0-211-38-5", 37, 5, 0.2);
 6     Bulk_quote b1("0-211-38-6", 44, 5, 0.2);
 7     basket.push_back(b);
 8     basket.push_back(b1);
 9     for (auto &i : basket)
10         sum += i.net_price(10);
11     return 0;
12 }
View Code

15.29

 1 int main()
 2 {
 3     double sum = 0.0;
 4     vector<shared_ptr<Quote>> basket;  
 5     basket.push_back(make_shared<Bulk_quote>("0-211-38-5", 37, 5, 0.2));
 6     basket.push_back(make_shared<Bulk_quote>("0-211-38-6", 44, 5, 0.2)); 
 7     for (auto x : basket)  
 8         sum += x->net_price(10);  
 9     cout << sum << endl;
10     return 0;
11 }
View Code

程序产生的结果会存在差异。

因为当通过Quote类型的对象调用虚函数net_price时,不实行动态绑定,调用的是Quote类中定义的版本;而通过Quote类型的指针调用虚函数net_price,实行动态绑定,而该指针实际指向Bulk_quote类中定义的版本。

15.30

  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <iterator>
  5 #include <initializer_list>
  6 #include <vector> 
  7 #include <string>
  8 #include <cstring>
  9 #include <deque>
 10 #include <list> 
 11 #include <forward_list>
 12 #include <array>
 13 #include <stack>
 14 #include <queue>
 15 #include <algorithm> 
 16 #include <functional>
 17 #include <map>
 18 #include <set> 
 19 #include <cctype>
 20 #include <unordered_map>
 21 #include <unordered_set>
 22 #include <memory> 
 23 #include <new> 
 24 #include <utility>
 25  
 26 using namespace std;
 27 using namespace std::placeholders;
 28 
 29 class Quote {
 30 public:
 31     Quote() = default;
 32     Quote(const string &book, double sales_price): bookNo(book), price(sales_price) { }
 33     string isbn() const { return bookNo; }
 34     virtual double net_price(size_t n) const { return n * price; }
 35     virtual Quote* clone() const & { return new Quote(*this); }
 36     virtual Quote* clone() && { return new Quote(move(*this)); }
 37 private:
 38     string bookNo;
 39 protected:
 40     double price = 0.0; 
 41 };
 42 
 43 class Bulk_quote : public Quote {
 44 public:
 45     Bulk_quote() = default;    
 46     Bulk_quote(const string &book, double sales_price, size_t n, double dis): Quote(book, sales_price), min_qty(n), discount(dis) { cout << "派生类带参构造函数
"; }
 47     double net_price(size_t n) const override;
 48     Bulk_quote* clone() const & { return new Bulk_quote(*this); }
 49     Bulk_quote* clone() && { return new Bulk_quote(move(*this)); }
 50 private:
 51     size_t min_qty = 0;
 52     double discount = 0.0;
 53 };
 54 
 55 double Bulk_quote::net_price(size_t n) const
 56 {
 57     if (n >= min_qty)
 58         return n * (1 - discount) * price;
 59     else
 60         return n * price;
 61 }
 62 
 63 double print_total(ostream &os, const Quote &item, size_t n)
 64 {
 65     double ret = item.net_price(n);
 66     os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << endl;
 67     return ret; 
 68 }
 69 
 70 class Basket {
 71 public:
 72     void add_item(const Quote &sale){ items.insert(shared_ptr<Quote>(sale.clone())); }
 73     void add_item(Quote &&sale){ items.insert(shared_ptr<Quote>(move(sale).clone())); }
 74     double total_receipt(ostream&) const;
 75 private:
 76     static bool compare(const shared_ptr<Quote> &lhs, const shared_ptr<Quote> &rhs){ return lhs->isbn() < rhs -> isbn(); }
 77     multiset<shared_ptr<Quote>, decltype(compare)*> items{compare};
 78 };
 79 
 80 double Basket::total_receipt(ostream &os) const
 81 {
 82     double sum = 0.0;
 83     for (auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)) {
 84         sum += print_total(os, **iter, items.count(*iter));
 85     }
 86     os << "Total Sale: " << sum << endl;
 87     return sum;
 88 }
 89 
 90 int main()
 91 {
 92     Basket bt;
 93     Quote q("legend", 25.0);
 94     Bulk_quote b("league", 37.0, 2, 0.2), b1 = b, b2 = b;
 95     bt.add_item(q);
 96     bt.add_item(b);
 97     bt.add_item(b1);
 98     bt.add_item(b2);
 99     bt.total_receipt(cout);
100     return 0;
101 }
View Code

15.31

原文地址:https://www.cnblogs.com/xzxl/p/7777725.html