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


    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

  • 相关阅读:
    设计模式之装饰者模式
    每天一点点
    生财有道
    地图的移动和缩放
    钱分割
    位运算
    ref和out
    使用startCoroutine制定倒计时
    静态类和单例类
    Awake和Start
  • 原文地址:https://www.cnblogs.com/xzxl/p/7777725.html
Copyright © 2020-2023  润新知