Handle Classes and inheritance

Source: Internet
Author: User

The previous section, "Containers and inheritance," http://blog.csdn.net/thefutureisour/article/details/7744790 mentioned:

For a container, if defined as a base class type, you cannot access the new members of the derived class through the container, and it is critical that the base class object can access the non-meaningful derived class members if it is defined as a derived class type and is not generally used to host objects of the base class, even if it is forcibly hosted with type conversions. The solution to this problem is to use a container to hold a pointer to the base class.

In C + +, this type of problem has a common workaround, called a handle class. It has largely completed two-part work:

1. Manage pointers. This is similar to the function of smart pointers

2. Implement polymorphism. With dynamic binding, pointers can point to both a base class and a derived class.

The design of the handle class needs to focus on two factors:

1. How to manage pointers

2. Whether to block the interfaces of the base classes and derived classes that it manages. This means that if we fully understand the interfaces that inherit hierarchically, then we can use them directly, or we encapsulate these interfaces and use the interface of the handle class itself.

The following is a more complex example to illustrate the problem:

The general idea of this example is to use a container (multiset) to simulate a shopping cart, which contains a lot of books, some books are sold at the original price, some books are discounted sales, and discount sales are divided into two strategies: buy more than only discount, buy less than the original price of sales. Finally, you can easily calculate the purchase of a variety of different types of books, under different discounts on how much money spent.

First, there are books that define different discounting strategies, and they are the inheritance hierarchy to manage when the handle class:

Base class item_base{public://Constructor Item_base (const std::string &book = "", double sales_price = 0.0) without using Discount Policy: ISBN ( Book), Price (Sales_price) {}//Returns the ISBN number std::string book () const {return ISBN;} Base class does not require a discount strategy for virtual double Net_price (std::size_t N) const{return n * PRICE;} destructor Virtual ~item_base () {};virtual item_base* clone () Const{return new Item_base (*this);} Private:std::string isbn;protected:double price;};/ /Save discount rate and Purchase quantity class//It has two derived classes that implement two discount modes class Disc_item:public item_base{public://default constructor 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) {}//pure virtual function: Prevents users from creating objects of this class double Net_price (std::size_t) const = 0;//will buy how many books to bind with the discount rate std::p air<std:: Size_t,double>discount_policy () Const{return Std::make_pair (quantity,discount);} Protected members for derived classes inherit protected://implement discount policy purchase volume std::size_t quantity;//discount rate double discount;};/ /Bulk Purchase discount strategy: discount is greater than a certain quantity class Bulk_item:public disc_item{public://constructor Bulk_item (const std::string& book = "", double sales_price = 0.0,std::size_t Qty = 0,double disc_rate = 0.0):D Isc_item (Book,sales_price,qty, Disc_rate) {}~bulk_item () {}double net_price (std::size_t) const; bulk_item* Clone () Const{return new Bulk_item (*this);}};/ /Bulk Purchase discount strategy: less than a certain amount of discount, greater than the portion of the original price processing 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) {} DOUBL E Net_price (std::size_t cnt) const {if (CNT <= quantity) return CNT * (1-discount) * Price;elsereturn CNT * Price-qua  ntity * discount * price;  } lds_item* Clone () const {return new Lds_item (*this); }};

Double Bulk_item::net_price (std::size_t cnt) const{if (CNT >= quantity) return CNT * (1-discount) * Price;elsereturn CNT * PRICE;}


The base class is not discounted. The direct derived class of the base class adds two members, each of which is the number of purchases to be discounted (or the number of times it will not be discounted, depending on its derived class), and the discount range. We define this class for the virtual base class. Complete by defining its net_price as a pure virtual function. The purpose of defining a virtual base class is because the class has no practical meaning and we do not want to create its object, and its derived classes define two different discounting strategies in detail. In both the base class and the derived class, the clone function is defined to return a copy of itself, which is used when the handle class is initialized. One thing to note here: In general, the declaration of a virtual function in the inheritance system should be the same, but there is an exception: the virtual function in the base class returns a pointer or reference to a base class (not necessarily the base class). A virtual function in a derived class can then return the derived class (or its pointer or reference) of the base class returned by the base class virtual function.

We then define a handle class to manage the base class or derived class object in this inheritance hierarchy:

Class sales_item{public://default constructor//pointer 0, not associated with whatever object, counter initialized to 1sales_item ():p (0), use (New std::size_t (1)) {}//Accept Item_ Constructor for base Object Sales_item (const item_base &item):p (Item.clone ()), use (New std::size_t (1)) {}//Copy control function: Manage counters and pointers Sales_ Item (const Sales_item &i):p (I.P), use (i.use) {++*use;} destructor ~sales_item () {decr_use ();} The assignment operator declares sales_item& operator= (const sales_item&);//overload member access operator Const Item_base *operator-> () const{if (p)// Returns a pointer to Item_base or its derived class return P;elsethrow std::logic_error ("unbound sales_item"); The overloaded Solver operator Const Item_base &operator* () const{if (p)//Returns an object of Item_base or its derived class return *p;elsethrow std::logic_error (" Unbound Sales_item ");} private://pointer to a base class, which can also be used to point to a derived class item_base *p;//point to a reference count std::size_t *use;//destructor Call this function to remove the pointer void Decr_use () {if (--*use = = 0 {delete p;delete use;}};

sales_item& sales_item::operator= (const Sales_item &RHS) {//reference count +1++*rhs.use;//Delete the original pointer decr_use ();// Point pointer to right operand p = rhs.p;//Copy reference count of right operand use = rhs.use;//return reference to left operand return *this;}


The handle class has two data members, each of which is a pointer to a reference count and a pointer to the base class (or its derived class). It also overloads the understanding of the primer operator and the arrow operator to access the objects in the inheritance hierarchy. It has 3 constructors: The first is the default constructor, the object is created with a reference count of 1, the pointer is empty, and the third is the copy constructor, which points to the object to which the pointer is pointing, and the reference count +1; The shape of the second constructor is a reference to the object of a base class. However, it is possible that a base class object may be a derived class object, but how can it be determined? This is determined by the base class and the Clone function in the derived class: what type the function returns, and what type it is.

With the front cushion, we can write a real shopping cart class:

The object of the associated container must be defined < manipulated by the inline bool Compare (const Sales_item &lhs,const sales_item &rhs) {return Lhs->book () < Rhs->book ();} Class basket{//pointer to function typedef BOOL (*COMP) (const sales_item&,const sales_item&);p ublic:typedef Std::multiset <Sales_item,Comp> set_type;typedef set_type::size_type size_type;typedef set_type::const_iterator const_iter ;//The default constructor, which determines the comparison function as Comparebasket (): the operation defined by the items (compare) {}//://Add an object to the container void Add_item (const sales_item &item) { Items.insert (item);} Returns the number of records returned to ISBN in the shopping basket size_type size (const sales_item &i) Const{return items.count (i);} Returns the price of all items in the basket double total () const;private://the associated container to store each trade, with a pointer to the function comp indicates the std::multiset<sales_item of the container element, comp> items;};

Double basket::total () const{//storage execution Total price double sum = 0.0;//upper_bound to skip all the same isbnfor (const_iter iter = Items.begin () ; ITER! = Items.end (); iter= Items.upper_bound (*iter)) {sum + = (*iter)->net_price (Items.Count (*iter));} return sum;}


The shopping cart is implemented using multiset, which means that the same ISBN books are stored continuously.

For the associative container, the < operation must be supported, but the definition < operation is not good, because our < is inferred by the ISBN sequence number, and "= =", but also to ISBN inference; but it is common sense that only ISBN, price, effective number of discounts, and discount rates are equal, the talent counts as equal , so doing so is very easy to mislead the class of users. The approach here is to define a comparison function compare, which is defined as an inline function, because it is used every time the element is inserted into the container. The process of associating this function with a container is very "loose", or, the coupling is very low:

Multiset<sales_item,comp> items means that we create an associative container called items, and the container type is sales_item. And the container infers the size of the container element by the function that the comp points to. This means that in the container's constructor, different inference operations can be implemented by initializing pointers to functions to different functions.

This class defines 3 functions that are used to add new books to the shopping cart, to return the number of an ISBN book, and to calculate the total price. The total function is worth explaining in detail:

The first is that the loop traversal is not done using iter++, but with iter = Items.upper_bound (*iter). For Multiset,upper_bound, the next position of the last element that points to a key is returned, so that the same book can be processed one at a time. Of course, the premise here is that for the same book, its discount strategy, the discount rate, and the amount of the discount to meet are consistent.

Second, the function in the loop body is very concise: The Sales_item object is obtained by the ITER solution, using the defined arrow operator to access the base class or the Net_price function of the derived class, and the derived class version number of the function needs an actual participation that shows how many books are discounted. This argument is obtained by invoking the count call of the associated container.

Handle Classes and inheritance

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.