zoukankan      html  css  js  c++  java
  • 第十五章 面向对象程序设计

    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

  • 相关阅读:
    [kuangbin带你飞]专题十二 基础DP1 E
    hdu 1203 I NEED A OFFER! (01背包)
    hdu 2602 Bone Collector (01背包)
    hdu 4513 吉哥系列故事——完美队形II (manacher)
    hdu 2203 亲和串 (KMP)
    hdu 1686 Oulipo (KMP)
    hdu 1251 统计难题 (字典树)
    hdu 2846 Repository (字典树)
    hdu 1711 Number Sequence (KMP)
    poj 3461 Oulipo(KMP)
  • 原文地址:https://www.cnblogs.com/xzxl/p/7777725.html
Copyright © 2011-2022 走看看