C++ Primer 學習筆記_72_物件導向編程

來源:互聯網
上載者:User

物件導向編程--控制代碼類與繼承[續]



三、控制代碼的使用

使用Sales_item對象可以更容易地編寫書店應用程式。代碼將不必管理Item_base對象的指標,但仍然可以獲得通過Sales_item對象進行的調用的虛行為。



1、比較兩個Sales_item對象

在編寫Function Compute銷售總數之前,需要定義比較Sales_item對象的方法。要用Sales_item作為關聯容器的關鍵字,必須能夠比較它們。關聯容器預設使用關鍵字類型的小於操作符,但是如果給Sales_item定義小於操作符,將使其含義不明;

幸好,關聯容器使我們能夠指定一個函數[或函數對象]用作比較函數。而且,在定義容器物件時必須提供比較函數。

定義一個函數用於比較Sales_item對象:

inline boolcompare(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迴圈,否則,就處理下一本書。

   我們使用multiset的 count成員確定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 boolcompare(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;}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.