25、C++ Primer 4th 筆記,物件導向編程(3)

來源:互聯網
上載者:User

1、在繼承情況下,衍生類別的範圍嵌套在基類範圍中。正是這種類範圍的層次嵌套使我們能夠直接存取基類的成員。

2、與基類成員同名的衍生類別成員將屏蔽對基類成員的訪問。可以使用範圍操作符訪問被屏蔽的基類成員。

3、在基類和衍生類別中使用同一名字的成員函數,其行為與資料成員一樣:在衍生類別範圍中衍生類別成員將屏蔽基類成員。即使函數原型不同,基類成員也會被屏蔽。

4、通過衍生類別對象調用基類對象時,實參必須與衍生類別中定義的版本相匹配,只有在衍生類別根本沒有定義該函數時,才考慮基類函數。

如果衍生類別想通過自身類型使用所有的重載版本,則衍生類別必須要麼重定義所有的版本,要麼一個也不重定義。

可以通過using為基類成員函數名稱進行聲明,將所有該函數的重載執行個體都加到衍生類別的範圍中。

5、名字尋找與繼承

1)首先確定進行函數調用的對象、引用或指標的靜態類型。

2)在該類中尋找函數,如果找不到,就在直接基類中尋找,如此循著類的繼承鏈往上找,直到找到該函數或者尋找完最後一個類。

    如果不能在類或其相關基類中找到該名字,則調用是錯誤的。

3)一旦找到了該名字,就進行常規類型檢查,通過查看找到的定義,來檢查該函數調用是否合法。

4)假定函數調用合法,編譯器就產生代碼。如果函數是虛函數且通過引用或指標調用,則編譯器產生代碼以確定根據對象的動態類型運行哪個函數版本,否則,編譯器產生代碼直接調用函數。

6、含有(或繼承)一個或多個純虛函數的類是抽象基類。除了作為抽象基類的衍生類別的對象的一部分,不能建立抽象類別型的對象。

7、容器與繼承

在容器中儲存有繼承關係的對象,如果定義成儲存基類對象,則衍生類別將被切割,如果定義成儲存衍生類別對象,則儲存基類對象又成問題(基類對象將被強制轉換成衍生類別對象,而衍生類別中定義的成員未被初始化)。

唯一的可行的選擇是容器中儲存對象的指標。但是需要使用者管理對象和指標。C++中一個通用的技術是封裝類(cover)或控制代碼類(handle)。用控制代碼類儲存和管理類指標。

8、封裝了繼承層次的控制代碼有兩個重要的設計考慮因素:

1)像對任何儲存指標的類一樣,必須確定對複製控制項做些什麼。封裝了繼承層次的控制代碼通常表現得像一個智能指標或者像一個值。

2)名柄類決定控制代碼介面屏蔽還是不屏蔽繼承層次,如果不屏蔽繼承層次,使用者必須瞭解和使用基本層次中的對象(objects in the underlying hierarchy)。

    控制代碼類經常需要在不知道對象的類型時分配已知對象的副本。解決這個問題的通用方法是定義虛操作進行複製,稱該操作為clone,如樣本中。

控制代碼類樣本

#ifndef BASKET_H#define BASKET_H#include <iostream>#include <string>#include <set>#include <map>#include <utility>#include <cstddef>// Item sold at an undiscounted price// derived classes will define various discount strategiesclass Item_base {friend std::istream& operator>>(std::istream&, Item_base&);friend std::ostream& operator<<(std::ostream&, const Item_base&);public:virtual Item_base* clone() const {return new Item_base(*this); }public:Item_base(const std::string &book = "", double sales_price = 0.0):          isbn(book), price(sales_price) { }std::string book() const { return isbn; }// returns total sales price for a specified number of items// derived classes will override and apply different discount algorithmsvirtual double net_price(std::size_t n) const { return n * price; }// no work, but virtual destructor needed // if base pointer that points to a derived object is ever deletedvirtual ~Item_base() { } private:std::string isbn;   // identifier for the itemprotected:double price;       // normal, undiscounted price};// class to hold discount rate and quantity // derived classes will implement pricing strategies using these dataclass Disc_item : public Item_base{public:std::pair<size_t, double> discount_policy() const{ return std::make_pair(quantity, discount); }// other members as beforedouble net_price(std::size_t) const = 0; //聲明為純虛函數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) { }protected:std::size_t quantity;  // purchase size for discount to applydouble discount;       // fractional discount to apply};// discount kicks in when a specified number of copies of same book are sold// the discount is expressed as a fraction to use to reduce the normal priceclass Bulk_item : public Disc_item {public:std::pair<size_t, double> discount_policy() const{ return std::make_pair(quantity, discount); }// other members as beforeBulk_item* clone() const { return new Bulk_item(*this); }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) { }// redefines base version so as to implement bulk purchase discount policydouble net_price(std::size_t) const;};// discount (a fraction off list) for only a specified number of copies, // additional copies sold at standard priceclass Lim_item : public Disc_item {public:Lim_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) { }// redefines base version so as to implement limited discount policydouble net_price(std::size_t) const;Lim_item* clone() const { return new Lim_item(*this); }std::pair<size_t, double> discount_policy() const{ return std::make_pair(quantity, discount); }};// use counted handle class for the Item_base hierarchy,控制代碼類class Sales_item {// let compare use the Item_base pointer to use Item_base compare function// this friend is needed for the hidden call to print_total, friend class Basket;   public:// default constructor: unbound handleSales_item(): p(0), use(new std::size_t(1)) { }// attaches a handle to a copy of the Item_base objectSales_item(const Item_base&); // copy control members to manage the use count and pointersSales_item(const Sales_item &i): p(i.p), use(i.use) {++*use; }~Sales_item(){ decr_use(); }Sales_item& operator=(const Sales_item&);// member access operatorsconst Item_base *operator->() const { return p; }const Item_base &operator*() const { return *p; }private:Item_base *p;         // pointer to shared itemstd::size_t *use;     // pointer to shared use count// called by both destructor and assignment operator to free pointersvoid decr_use() { if (--*use == 0)    {   delete p;    delete use;   } }};bool compare(const Sales_item &, const Sales_item &);// holds items being purchasedclass Basket {// type of the comparison function used to order the multisettypedef bool (*Comp)(const Sales_item&, const Sales_item&);std::multiset<Sales_item, Comp> items;public:// useful typedefs modeled after corresponding container typestypedef std::multiset<Sales_item, Comp>::size_type size_type;typedef std::multiset<Sales_item, Comp>::const_iterator const_iter;// workaround MS compiler bug: must explicitly pass function addressBasket(): items(&compare) { }  // initialze the comparatorvoid display(std::ostream&) const;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;  // sum of net prices for all items in the basket};inlineSales_item::Sales_item(const Item_base &item):p(item.clone()), use(new std::size_t(1)) { }// compare defines item ordering for the multiset in Basketinline bool compare(const Sales_item &lhs, const Sales_item &rhs) {return lhs->book() < rhs->book();} #endif#include <algorithm>using std::multiset; using std::map; using std::pair; using std::size_t;using std::string; using std::ostream; using std::endl; using std::min;using std::cout;// debugging routine to check contents in a Basketvoid Basket::display(ostream &os) const{os << "Basket size: " << items.size() << endl;// print each distinct isbn in the Basket along with// count of how many copies are ordered and what their price will be// upper_bound returns an iterator to the next item in the setfor (const_iter next_item = items.begin();next_item != items.end();next_item = items.upper_bound(*next_item)){// we know there's at least one element with this key in the Basketos << (*next_item)->book() << " occurs " << items.count(*next_item) << " times" << " for a price of " << (*next_item)->net_price(items.count(*next_item)) << endl;}}void print_total(ostream &, const Item_base&, size_t);// calculate and print price for given number of copies, applying any discounts void print_total(ostream &os,  const Item_base &item, size_t n){os << "ISBN: " << item.book() // calls Item_base::book<< "\tnumber sold: " << n << "\ttotal price: "// virtual call: which version of net_price to call is resolved at run time<< item.net_price(n) << endl;}double Basket::total() const{double sum = 0.0;    // holds the running total for (const_iter iter = items.begin(); iter != items.end();iter = items.upper_bound(*iter)){// we know there's at least one element with this key in the Basketprint_total(cout, *(iter->p), items.count(*iter));// virtual call to net_price applies appropriate discounts, if anysum += (*iter)->net_price(items.count(*iter));}return sum;}// use-counted assignment operator; use is a pointer to a shared use countSales_item&Sales_item::operator=(const Sales_item &rhs){++*rhs.use;decr_use();p = rhs.p;use = rhs.use;return *this;}// if specified number of items are purchased, use discounted price double Bulk_item::net_price(size_t cnt) const{if (cnt >= quantity)return cnt * (1 - discount) * price;elsereturn cnt * price;}// use discounted price for up to a specified number of items// additional items priced at normal, undiscounted pricedouble Lim_item::net_price(size_t cnt) const{size_t discounted = min(cnt, quantity);size_t undiscounted = cnt - discounted;return discounted * (1 - discount) * price + undiscounted * price;}int main(){//...return 1;}

控制代碼類樣本

9、虛函數的重寫中,衍生類別的傳回型別必須與基類執行個體的傳回型別完全符合,但有一個例外:如果虛函數的基類執行個體返回類類型的引用或指標,則該虛函數的衍生類別執行個體可以返回基類執行個體返回的類型的衍生類別對象(或者是類類型的指標或引用)。

10、在定義關係運算子時,如定義==,<=時,其邏輯要一致。

參考

[1] multiset使用

http://blog.163.com/zhoumhan_0351/blog/static/399542272010396030501/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.