Primer C++笔记记录(第十五章)

本书为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) 输出basebasename
derived::print(ostream& os) 调用base::print,然后输出derivedi
应该把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)

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦