《C++ Primer》第15章 15.2节习题答案

《C++ Primer》第15章 面向对象程序设计

本章介绍了面向对象程序设计的两个重要概念:继承和动态绑定,包括:

□●继承、基类、派生类的基本概念。

□●虚函数和虚基类。

□●继承中的访问控制、类作用域、构造函数和拷贝控制等问题。

本章练习的最重要目的是让读者理解这些基本概念。掌握根据实际问题特点设计合理的类层次的能力。特别是对比较大的例子——文本查询程序进行修改,练习类层次的设计,来更好地掌握这些基本能力。

15.2节 定义基类和派生类 习题答案

练习15.1:什么是虚成员?

【出题思路】

熟悉理解虚函数、虚成员的定义。

【解答】

在类中被声明为virtual 的成员,基类希望这种成员在派生类中重定义。除了构造函数外,任意非 static成员都可以为虚成员。

练习15.2:protected访问说明符与private有何区别?

【出题思路】

区分protected和private的访问权限控制的不同之处。

【解答】

protected 为受保护的访问标号,protected 成员可以被该类的成员、友元和派生类成员(非友元)访问,而不可以被该类型的普通用户访问。而 private 成员只能被基类的成员和友元访问,派生类不能访问。

练习15.3:定义你自己的Quote类和print_total函数。

【出题思路】

书中示例,作为基类用于后续练习题。

【解答】

#include <iostream>
#include <string>

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(std::size_t n)const
    {
        return n * price;
    }

    virtual ~Quote() = default;//对析构函数进行动态绑定

private:
    string bookNo;//书籍的ISBN编号
protected:
    double price = 0.0;//代表普通状态下不打折的价格
};

double print_total(ostream &os, const Quote &item, size_t n)
{
    //根据传入item形参的对象类型调用Quote::net_price
    //或者Bulk_quote::net_price
    double ret = item.net_price(n);
    os << "ISBN: " << item.isbn() << " # sold: " << n
       << "  total due: " << ret << endl;
    return ret;
}

int main()
{
    Quote quote("XN4098", 50);
    //cout是ostream的对象
    print_total(cout , quote, 6);

    return 0;
}

运行结果:ISBN: XN4098 # sold: 6  total due: 300

练习15.4:下面哪条声明语句是不正确的?请解释原因。

class Base { . . . };
(a) class Derived : public Derived { . . . };
(b) class Derived : private Base {  . . . };
(c) class Derived : public Base;

【出题思路】

熟悉派生类的定义、声明要求。

【解答】

(a)错误,不能用类本身作为类的基类。

(c)声明类时,不可以包含派生列表。

练习15.5:定义你自己的Bulk_quote类。

【出题思路】

继承方式练习,Quote作为基类。

【解答】

#include <iostream>
#include <string>

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(std::size_t n)const
    {
        return n * price;
    }

    virtual ~Quote() = default;//对析构函数进行动态绑定

private:
    string bookNo;//书籍的ISBN编号
protected:
    double price = 0.0;//代表普通状态下不打折的价格
};

double print_total(ostream &os, const Quote &item, size_t n)
{
    //根据传入item形参的对象类型调用Quote::net_price
    //或者Bulk_quote::net_price
    double ret = item.net_price(n);
    os << "ISBN: " << item.isbn() << " # sold: " << n
       << "  total due: " << ret << endl;
    return ret;
}

class Bulk_quote: public Quote
{
public:
    //书号, 售价,适用折扣政策的最低购买量,折扣额
    Bulk_quote(const std::string &book, double sales_price, size_t qty, double disc)
        :Quote(book, sales_price), min_qty(qty), discount(disc)
    {   }

    //覆盖基类的函数版本以实现基于大量购买的折扣政策
    double net_price(std::size_t count) const override//如果不加override,net_price这个函数也是虚函数
    {
        if(count >= min_qty)
            return count * (1 - discount) * price;
        else
            return count * price;
    }

private:
    size_t min_qty;//适用折扣政策的最低购买量
    double discount;//以小数表示的折扣额
};

int main()
{
    Quote quote("XN5029", 30);
    print_total(cout, quote, 6);

    Bulk_quote bulkQuote("XN5029", 30, 5, 0.2);
    print_total(cout, bulkQuote, 6);

    return 0;
}

运行结果:

 

 练习15.6:将Quote和Bulk_quote的对象传给15.2.1节(第529页)练习中的print_total函数,检查该函数是否正确。

【出题思路】

练习基类和派生类的使用。

【解答】

编写简单的主函数,声明Quote和Bulk_quote对象,调用print_total即可。

#include <iostream>
#include <string>

using std::string;
using std::cout;
using std::endl;

class Quote
{
public:
    Quote() = default;
    Quote(const std::string &book, double sales_price):
    bookNo(book), price(sales_price)
    {
    }

    std::string isbn() const
    {
        return bookNo;
    }

    //返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
    virtual double net_price(std::size_t n) const
    {
        cout << "net_price ===================Quote" << endl;
        return n * price;
    }
    virtual void currentClass() const
    {
        cout << "current Class is ================Quote" << endl;
    }

    virtual ~Quote() = default;//对析构函数进行动态绑定

private:
    std::string bookNo;//书籍的ISBN编号

protected:
    double price = 0.0;//代表普通状态下不打折的价格
};

double print_total(std::ostream &os, const Quote &item, size_t n)
{

    //根据传入item形参的对象类型调用Quote::net_price或者Bulk_quote::net_price
    double ret = item.net_price(n);
    os << "ISBN:" << item.isbn() << " # sold:" << n << " total due: " << ret << endl;
    item.currentClass();
    return ret;
}

class Bulk_quote: public Quote
{
public:
    Bulk_quote() = default;
    //书号, 售价,适用折扣政策的最低购买量,折扣额
    Bulk_quote(const std::string &book, double sales_price, size_t qty, double disc)
    :Quote(book, sales_price), min_qty(qty), discount(disc)
    {

    }
    //覆盖基类的函数版本以实现基于大量购买的折扣政策
    double net_price(size_t cnt) const override//如果不加override,net_price这个函数也是虚函数 p528
    {
        cout << "net_price ================Bulk_quote" << endl;
        if(cnt >= min_qty)
        {
            return cnt * discount * price;
        }
        else
        {
            return cnt * price;
        }
    }
    //如果不加const,print_total函数里调用的是基类的currentClass,net_pricce函数也同理·
    void currentClass() const override
    {
        cout << "current Class is ================Bulk_quote" << endl;
    }


private:
    size_t min_qty;//适用折扣政策的最低购买量
    double discount;//以小数表示的折扣额
};

int main()
{
    Quote quote("NO423", 50);
    //cout是ostream的对象
    print_total(cout, quote, 8);
    quote.currentClass();
    cout << "\n\n" << endl;

    Bulk_quote bulk_quote("NO423", 50, 8, 0.8);
    print_total(cout, bulk_quote, 8);
    bulk_quote.currentClass();

    std::cout << "Hello, World!\n";
    return 0;
}

运行结果:

 

练习15.7:定义一个类使其实现一种数量受限的折扣策略,具体策略是:当购买书籍的数量不超过一个给定的限量时享受折扣,如果购买量一旦超过了限量,则超出的部分将以原价销售。

【出题思路】

本题练习特定策略的类定义。

【解答】

#include <iostream>
#include <string>

using std::string;
using std::cout;
using std::endl;

class Quote
{
public:
    Quote() = default;
    Quote(const std::string &book, double sales_price):
        bookNo(book), price(sales_price)
    {
    }

    std::string isbn() const
    {
        return bookNo;
    }

    //返回给定数量的书籍的销售总额,派生类改写并使用不同的折扣计算方法
    virtual double net_price(std::size_t n) const
    {
        cout << "net_price ===================Quote" << endl;
        return n * price;
    }

    virtual ~Quote() = default;//对析构函数进行动态绑定

private:
    std::string bookNo;//书籍的ISBN编号

protected:
    double price = 0.0;//代表普通状态下不打折的价格
};

double print_total(std::ostream &os, const Quote &item, size_t n)
{
    //根据传入item形参的对象类型调用Quote::net_price或者Bulk_quote::net_price
    double ret = item.net_price(n);
    os << "ISBN:" << item.isbn() << " # sold:" << n << " total due: " << ret << endl;
    return ret;
}

class Limited_quote: public Quote
{
public:
    Limited_quote() = default;
    //书号, 售价,适用折扣政策的最低购买量,折扣额
    Limited_quote(const std::string &book, double sales_price, size_t qty, double disc)
        :Quote(book, sales_price), min_qty(qty), discount(disc)
    {

    }
    //覆盖基类的函数版本以实现基于大量购买的折扣政策
    double net_price(size_t cnt) const override//如果不加override,net_price这个函数也是虚函数 p528
    {
        cout << "net_price ================Bulk_quote" << endl;
        if(cnt <= min_qty)
        {
            return cnt * discount * price;
        }
        else
        {
            return min_qty * discount * price + (cnt - min_qty) * price;
        }
    }

private:
    size_t min_qty;//适用折扣政策的最低购买量
    double discount;//以小数表示的折扣额
};

int main()
{
    Quote quote("NO423", 50);
    //cout是ostream的对象
    print_total(cout, quote, 8);
    cout << "\n\n" << endl;

    Limited_quote limited_quote("NO423", 50, 8, 0.8);
    print_total(cout, limited_quote, 8);
    print_total(cout, limited_quote, 9);
    std::cout << "Hello, World!\n";
    return 0;
}

运行结果:

 练习15.8:给出静态类型和动态类型的定义。

【出题思路】

区分静态类型和动态类型,熟悉其定义内容。

【解答】

静态类型在编译时就已经确定了,它是变量声明时的类型或表达式生成的类型;而动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行时才能知道。如:Quote *pQuote =new Bulk_quote;,指针pQuote的静态类型是Quote,在编译时就已经确定了。但是它的动态类型是Bulk_quote,直到运行时才能知道它指向的是基类还是派生类。如果一个变量非指针也非引用,则它的静态类型和动态类型永远一致。但基类的指针或引用的动态类型可能与其动态类型不一致。

练习15.9:在什么情况下表达式的静态类型可能与动态类型不同?请给出三个静态类型与动态类型不同的例子。

【出题思路】

具体举例说明静态类型与动态类型的不同。

【解答】

Bulk_quote bulk;
Quote *pQuote = &bulk;
Quote &rQuote = bulk;
//传递给item的如果是派生类对象,即是静态类型和动态类型不同的情况
double print_total(ostream &os, const Quote &item, size_t n);

 练习15.10:回忆我们在8.1节(第279页)进行的讨论,解释第284页中将ifstream传递给Sales_data的read函数的程序是如何工作的。

【出题思路】

理解静态类型和动态类型。

【解答】

在要求使用基类型对象的地方,可以使用派生类型的对象来代替,是静态类型和动态类型不同的典型例子。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值