zoukankan      html  css  js  c++  java
  • C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]

    面向对象编程

    --句柄类与继承[]



    三、句柄的使用

    使用Sales_item对象能够更easy地编写书店应用程序。代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对象进行的调用的虚行为。



    1、比較两个Sales_item对象

    在编写函数计算销售总数之前,须要定义比較Sales_item对象的方法。要用Sales_item作为关联容器的keyword,必须能够比較它们。关联容器默认使用keyword类型的小于操作符,可是假设给Sales_item定义小于操作符,将使其含义不明;

    幸好,关联容器使我们能够指定一个函数[或函数对象]用作比較函数。并且,在定义容器对象时必须提供比較函数。

    定义一个函数用于比較Sales_item对象:

    inline bool
    compare(const Sales_item &lsh,const Sales_item &rhs)
    {
        return lsh -> book() < rhs -> book();
    }
    

    该函数使用Sales_item->操作符,该操作符返回Item_base对象的指针,哪个指针用于获取并执行成员的book操作,该成员返回ISBN



    2、使用带比較器的关联容器

    对于比較函数,它必须作为容器的一部分而存储,不论什么在容器中添加�或查找元素的操作都要使用比較函数。

    要有效地工作,关联容器须要对每一个操作使用同一比較函数。然而,期望用户每次记住比較函数是不合理的,尤其是,没有办法检查每一个调用使用同一比較函数。因此,容器记住比較函数是有意义的。通过将比較器存储在容器对象中,能够保证比較元素的每一个操作将一致地进行。

    为了存储比較器,它须要知道比較器类型。形參类型也不须要与 key_type全然匹配,应该同意能够转换为key_type的随意形參类型。

    所以,要使用Sales_item的比較函数,在定义multiset必须指定比較器类型。在我们的样例中,比較器类型是接受两个constSales_item 引用并返回bool值的函数。

        typedef bool (*Comp)(const Sales_item &,const Sales_item &); 
    

    Comp定义为函数类型指针的同义词,该函数类型与我们希望用来比較 Sales_item对象的比較函数相匹配

    接着须要定义multiset,保存Sales_item类型的对象并在它的比較函数中使用这个Comp类型。关联容器的每一个构造函数使我们能够提供比較函数的名字

    能够这样定义使用compare函数的空multiset:

        std::multiset<Sales_item,Comp> items(compare);
    

    这个定义是说,items是一个multiset,它保存Sales_item对象并使用Comp类型的对象比較它们。multiset是空的—— 我们没有提供不论什么元素,但我们的确提供了一个名为compare的比較函数。当在items添加�查找元素,compare函数multiset进行排序。



    3、容器与句柄类

    我们定义一个Basket类,用以跟踪销售并计算购买价格:

    class Basket
    {
        typedef bool (*Comp)(const Sales_item &,const Sales_item &);
    public:
        typedef multiset<Sales_item,Comp> set_type;
        typedef set_type::size_type size_type;
        typedef set_type::const_iterator const_iter;
    
        Basket():items(compare) {}
    
        void add_item(const Sales_item &item)
        {
            items.insert(item);
        }
        size_type size(const Sales_item &i) const
        {
            return items.count(i);
        }
    
        double total() const;
    
    private:
        multiset<Sales_item,Comp> items;
    };
    

    该类定义了一个构造函数,即Basket默认构造函数。该类须要自己的默认构造函数,以便将compare传递给建立items成员的multiset构造函数



    4、使用句柄执行虚函数

    Basket类中的total函数用于返回购物篮中全部物品的价格:

    double Basket::total() const
    {
        double sum = 0.0;
    
        for (set_type::iterator iter = items.begin();
                iter != items.end();
                iter = items.upper_bound(*iter))
        {
            sum += (*iter) -> net_price(items.count(*iter));
        }
    
        return sum;
    }
    

       for循环中的“增量”表达式非常有意思。与读每一个元素的一般循环不同,我们推进iter指向下一个键。调用upper_bound函数以跳过与当前键匹配的全部元素,upper_bound函数的调用返回一个迭代器,该迭代器指向与iter键同样的最后一个元素的下一元素,,该迭代器指向集合的末尾或下一本书。測试iter的新值,假设与items.end()相等,则跳出for循环,否则,就处理下一本书。

       我们使用multisetcount成员确定multiset中的多少成员具有同样的键(,同样的isbn),并且使用该数目作为实參调用net_price函数。

    for循环的循环体调用net_price函数,阅读这个调用须要一点技巧:

    		sum += (*iter) -> net_price(items.count(*iter)); 
    

    iter解引用获得基础Sales_item对象,对该对象应用Sales_item类重载的箭头操作符,该操作符返回句柄所关联的基础Item_base对象的指针,用该Item_base对象指针调用net_price函数,传递具有同样isbn的图书的count作为实參。net_price虚函数,所以调用的定价函数的版本号取决于基础Item_base对象的类型


    //P511 习题15.35
    //1 in item.h
    #ifndef ITEM_H_INCLUDED
    #define ITEM_H_INCLUDED
    
    #include <string>
    #include <utility>
    
    class Item_base
    {
    public:
        Item_base(const std::string &book = "",
                  double sales_price = 0.0):
            isbn(book),price(sales_price) {}
    
        std::string book() const
        {
            return isbn;
        }
    
        virtual double net_price(std::size_t n) const
        {
            return price * n;
        }
    
        virtual Item_base *clone() const
        {
            return new Item_base(*this);
        }
    
        virtual ~Item_base() {}
    
    private:
        std::string isbn;
    
    protected:
        double price;
    };
    
    class Disc_item : public Item_base
    {
    public:
        Disc_item(const std::string &book = "",
                  double sales_price = 0.0,
                  std::size_t qty = 0,
                  double disc_rate = 0.0):
            Item_base(book,sales_price),quantity(qty),discount(disc_rate) {}
    
        virtual double net_price(std::size_t ) const = 0;
    
        std::pair<std::size_t,double> discount_policy() const
        {
            return std::make_pair(quantity,discount);
        }
    
    protected:
        std::size_t quantity;
        double discount;
    };
    
    class Bulk_item : public Disc_item
    {
    public:
        Bulk_item(const std::string &book = "",
                  double sales_price = 0.0,
                  std::size_t qty = 0,
                  double disc_rate = 0.0):
            Disc_item(book,sales_price,qty,disc_rate) {}
    
        virtual double net_price(std::size_t n) const
        {
            if (n >= quantity)
            {
                return n * (1 - discount) * price;
            }
            else
            {
                return n * price;
            }
        }
    
        virtual Bulk_item *clone() const
        {
            return new Bulk_item(*this);
        }
    };
    
    class Lds_item : public Disc_item
    {
    public:
        Lds_item(const std::string &book = "",
                 double sales_price = 0.0,
                 std::size_t qty = 0,
                 double disc_rate = 0.0):
            Disc_item(book,sales_price,qty,disc_rate) {}
    
        virtual double net_price(std::size_t n) const
        {
            if (n <= quantity)
            {
                return n * (1 - discount) * price;
            }
            else
            {
                return n * price - quantity * discount * price;
            }
        }
    
        virtual Lds_item *clone() const
        {
            return new Lds_item(*this);
        }
    };
    
    #endif // ITEM_H_INCLUDED
    

    //2 in sales_item.h
    #ifndef SALES_ITEM_H_INCLUDED
    #define SALES_ITEM_H_INCLUDED
    
    #include "item.h"
    #include <stdexcept>
    
    class Sales_item
    {
    public:
        Sales_item():p(0),use(new std::size_t(1)) {}
        Sales_item(const Item_base &rhs):
            p(rhs.clone()),use(new std::size_t(1)) {}
    
        Sales_item(const Sales_item &rhs):p(rhs.p),use(rhs.use)
        {
            ++ *use;
        }
    
        ~Sales_item()
        {
            decr_use();
        }
    
        Sales_item &operator=(const Sales_item &rhs);
    
        const Item_base *operator->() const
        {
            if (p)
            {
                return p;
            }
            else
            {
                throw std::logic_error("unbound Sales_item");
            }
        }
    
        const Item_base &operator*() const
        {
            if (p)
            {
                return *p;
            }
            else
            {
                throw std::logic_error("unbound Sales_item");
            }
        }
    
    private:
        Item_base *p;
        std::size_t *use;
    
        void decr_use()
        {
            if (-- *use)
            {
                delete p;
                delete use;
            }
        }
    };
    
    #endif // SALES_ITEM_H_INCLUDED
    

    //3 in sales_item.cpp
    #include "sales_item.h"
    
    Sales_item &Sales_item::operator=(const Sales_item &rhs)
    {
        ++ * rhs.use;
        decr_use();
    
        p = rhs.p;
        use = rhs.use;
    
        return *this;
    }
    

    //4 in basket.h
    #ifndef BASKET_H_INCLUDED
    #define BASKET_H_INCLUDED
    
    #include "sales_item.h"
    #include <set>
    
    inline bool
    compare(const Sales_item &lhs,const Sales_item &rhs)
    {
        return lhs -> book() < rhs -> book();
    }
    
    class Basket
    {
        typedef bool (*Comp)(const Sales_item &,const Sales_item &);
    public:
        typedef std::multiset<Sales_item,Comp> set_type;
        typedef set_type::size_type size_type;
        typedef set_type::const_iterator const_iter;
    
        Basket():items(compare){}
    
        void add_item(const Sales_item &item)
        {
            items.insert(item);
        }
    
        size_type size(const Sales_item &item) const
        {
            return items.count(item);
        }
    
        double total() const;
    
    private:
        std::multiset<Sales_item,Comp> items;
    
    };
    
    #endif // BASKET_H_INCLUDED
    

    //5 in basket.cpp
    #include "basket.h"
    
    double Basket::total() const
    {
        double sum = 0.0;
    
        for (set_type::iterator iter = items.begin();
                iter != items.end();
                iter = items.upper_bound(*iter))
        {
            sum += (*iter) -> net_price(items.count(*iter));
        }
    
        return sum;
    }
    

    //6 in main.cpp
    #include <iostream>
    #include "item.h"
    #include "basket.h"
    
    using namespace std;
    
    int main()
    {
        Basket basket;
        Sales_item item1(Bulk_item("7-115-14554-7",99,20,0.2));
        Sales_item item2(Item_base("7-115-14554-7",39));
        Sales_item item3(Lds_item("7-115-14554-7",50,200,0.2));
        Sales_item item4(Bulk_item("7-115-14554-7",99,20,0.2));
    
        basket.add_item(item1);
        basket.add_item(item2);
        basket.add_item(item3);
        basket.add_item(item4);
    
        cout << basket.total() << endl;
    }
    

  • 相关阅读:
    计算机网络协议如何学习之换位思考
    tcp/ip协议
    JSP页面中的元素
    动态网页脚本语言
    php的学习经验
    jsp、php和asp之间的区别
    Reactor 线程模型
    Hadoop集群搭建
    hadoop单点配置
    Docker 安装脚本
  • 原文地址:https://www.cnblogs.com/blfshiye/p/3764203.html
Copyright © 2011-2022 走看看