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循環,否則,就處理下一本書。
? ?我們使用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對象的類型。
//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; }
轉載于:https://www.cnblogs.com/blfshiye/p/3764203.html
總結
以上是生活随笔為你收集整理的C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件夹查找文件(一个文件夹文件查找函数
- 下一篇: endl与'\n'的区别