Handle class and inheritance

Source: Internet
Author: User

The previous section "container and inheritance" was mentioned at http://blog.csdn.net/thefutureisour/article/details/7744790:

If a container is defined as a base class type, the newly added member of the derived class cannot be accessed through the container. If it is defined as a derived class type, it generally cannot be used to host the objects of the base class, even if the type conversion is forcibly carried, the base class object can access meaningless derived class members, which is very dangerous. The solution to this problem is to use the container to save the pointer of the base class.

In C ++, there is a common solution to such problems, called the handle class. It basically completes two aspects of work:

1. Manage pointers. This is similar to smart pointer functions.

2. Implement polymorphism. By using dynamic binding, a pointer can be directed either to the base class or to a derived class.

Two factors need to be taken into account in the design of the handle class:

1. How to manage pointers

2. Whether to block the interfaces of the base class managed by it and the derived class. This means that if we fully understand the inherited interfaces, we can directly use them; or we can encapsulate these interfaces and use the interfaces of the handle class.

The following describes the problem through a complex example:

The general idea of this example is to use a container (Multiset) to simulate a shopping cart, which contains many books. Some books are sold at the original price, and some books are sold at a discount, in addition, there are two kinds of discount sales strategies: Buy More to get a discount; buy less to get a discount, more than the original price sales. Finally, we can easily calculate the total cost of purchasing different types of books at different discounts.

First, define books with different discount policies. The Inheritance layers to be managed by the handle class are as follows:

 

// The base class item_base {public: // constructor item_base (const STD: string & book = "", double sales_price = 0.0) that does not use the discount policy ): ISBN (book), price (sales_price) {}// return ISBN No. STD: String book () const {return ISBN ;} // The base class does not require the discount policy 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 ;}; // The class that saves the discount rate and the purchased quantity // It has two Derived classes and implements 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 this class Object doubl E net_price (STD: size_t) const = 0; // bind the number of books to the discount rate STD: pair <STD: size_t, double> discount_policy () const {return STD: make_pair (quantity, discount);} // Number of bought STD: size_t quantity; // discount rate double discount;}; // discount policy for batch purchase: 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): Di SC _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) ;}; // batch purchase discount policy: discount is given only when the discount is less than a certain number. The larger part deals with 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) {} double net_price (STD: size_t CNT) const {If (CNT <= quantity) return CNT * (1-discount) * price; elsereturn CNT * price-quantity * 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;}

Basically, there is no discount. Two members are added to the direct derived class of the base class, which is the number of books purchased for discount (or the number of books not discounted after the number is exceeded, depending on its derived class ), and the discount. We define this class as a virtual base class. It is done by defining its net_price as a pure virtual function. It is defined as a virtual base class because this class has no practical significance. We do not want to create its objects, and its derived Classes define two different discount policies. Both the base class and the derived class define the clone function to return a copy of itself. They will be used when the handle class is initialized. Note: In general, the declaration of virtual functions 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 pointing to a base class (not necessarily the base class, then, the virtual function in the derived class can return the derived class of the base class returned by the base class virtual function (or its pointer or reference ).

Then, we define a handle class to manage the base class or derived class objects in this inheritance level:

 

Class sales_item {public: // default constructor // the pointer is set to 0 and is not associated with any object. The counter is initialized to 1sales_item (): p (0), use (new STD :: size_t (1) {}// accepts the constructor sales_item (const item_base & item) of the item_base object: P (item. clone (), use (new STD: size_t (1) {}// copy control function: Manage counter and pointer sales_item (const sales_item & I): p (I. p), use (I. use) {++ * use;} // destructor ~ Sales_item () {decr_use () ;}// value assignment operator sales_item & operator = (const sales_item &); // reload the member access operator const item_base * operator-> () const {If (p) // return the pointer to item_base or its derived class return P; elsethrow STD: logic_error ("unbound sales_item ");} // The overload relief operator const item_base & operator * () const {If (p) // returns the item_base or its derived class Object return * P; elsethrow STD :: logic_error ("unbound sales_item");} PRIVATE: // pointer to the base class, which can also be used to point to the item_base * P derived class; // point to reference count STD: size_t * use; // The Destructor calls this function to delete the 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 the pointer to the right operand P = RHS. p; // copy the reference count of the right operand use = RHS. use; // return the reference of the left operand return * This ;}

The handle class has two data members: the pointer pointing to the reference count and the pointer pointing to the base class (or the pointer of its derived class ). We also reload the introduction operators and arrow operators to access objects in the inheritance level. There are three constructor types: the first is the default constructor, and an object with a reference count of 1 and a pointer of null is created. The third is the copy constructor, let the pointer point to the object pointed to by the real parameter pointer, and the reference count is + 1. The form parameter of the second constructor is a reference of a base class object, however, real parameters may be base class objects or derived class objects. How can we determine? Here, the clone function in the base class and derived class is used to determine the type and type returned by the function.

 

With the preparations above, we can write a real shopping cart class:

 

// The object associated with the container must define <operation inline bool compare (const sales_item & LHS, const sales_item & RHs) {return LHS-> book () <RHS-> book ();} class basket {// pointer to the function typedef bool (* comp) (const sales_item &, const sales_item &); Public: typedef STD :: multiset <sales_item, comp> set_type; typedef set_type: size_type; typedef set_type: const_iterator const_iter; // The default constructor determines the comparison function as comparebasket (): items (compare) {}// defined operation: // Add an object void add_item (const sales_item & item) {items. insert (item) ;}// return the number of ISBN records returned in the 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: // associated container to store each transaction, use the pointer to the function comp to specify the comparison STD: Multiset <sales_item, comp> items;} of container elements ;};

Double basket: Total () const {// double sum = 0.0; // upper_bound is used to skip all identical 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 books with the same ISBN are continuously stored.

For associated containers, the <operation must be supported, but the definition <operation is not good, because our <is determined by the ISBN serial number, and "=" is also determined by the ISBN; however, it is common sense that only ISBN, price, discount effective quantity, and discount rate are equal, so it is easy to mislead users. The method used here is to define a comparison function compare and define it as an inline function, because it is used every time an element is inserted into the container. The process of associating this comparison function with the container is very "loose", or the coupling is very low:

Multiset <sales_item, comp> items; indicates that an associated container named items is created. The container type is sales_item. In addition, the container uses the function pointed to by comp to determine the size of the container element. This means that in the constructor of the container, different judgment operations can be implemented by initializing the pointer pointing to the function to different functions.

This class defines three functions to add new books to the shopping cart, return the number of ISBN books, and calculate the total price. The total function is worth a careful explanation:

First, loop traversal is not completed by ITER ++, but by iter = items. upper_bound (* ITER ). For Multiset, upper_bound returns the next position pointing to the last element of a key, so that you can process the same book at a time. Of course, there is a premise here that for the same book, its discount strategy, discount rate, and the quantity satisfied by the discount are consistent.

Secondly, the function in the loop body is very concise: ITER obtains the sales_item object, and uses the defined arrow operator to access the net_price function of the base class or derived class, the version of the derived class of this function requires a real parameter indicating how many books are available for discounts. This real parameter is obtained by calling the Count call of the associated container.

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.