【正文】
face. Instead, these derivations are often referred to as implementation inheritance. The derived class uses the inherited class in its implementation but does not expose the fact of the inheritance as part of its interface. As we39。 } }。 } }。 // error: basemem is private in the derived class Both Public_derived and Private_derived inherit the basemem function. That member retains its access level when the inheritance is public, so d1 can call basemem. In Private_derived, the members of Base are private。 // ok: basemem is public ()。 Private_derived d2。 All classes that inherit from Base have the same access to the members in Base, regardless of the access label in their derivation lists. The derivation access label controls the access that users of the derived class have to the members inherited from Base: Base b。 struct Private_derived : private Base { int use_base() { return i。 struct Public_derived : public Base { int use_base() { return i。 // public member protected: int i。 Each Bulk_item object contains four data elements: It inherits isbn and price from Item_base and defines min_qty and discount. These latter two members specify the minimum quantity and the discount to apply once that number of copies are purchased. Derived Classes and virtual Functions Ordinarily, derived classes redefine the virtual functions that they inherit, although they are not requried to do so. If a derived class does not redefine a virtual, then the version it uses is the one defined in its base class. A derived type must include a declaration for each inherited member it intends to redefine. Our Bulk_item class says that it will redefine the _price function but will use the inherited version of book. Public, Private, and Protected Inheritance Access to members defined within a derived class is controlled in exactly the same way as access is handled for any other class (Section , p. 432). A derived class may define zero or more access labels that specify the access level of the members following that label. Access to the members the class inherits is controlled by a bination of the access level of the member in the base class and the access label used in the derived class39。 // minimum purchase for discount to apply double discount。s useful to know is that the access label determines the access to the inherited members. When we want to inherit the interface of a base class, then the derivation should be public. A derived class inherits the members of its base class and may define additional members of its own. Each derived object contains two parts: those members that it inherits from its base and those it defines itself. Typically, a derived class (re)defines only those aspects that differ from or extend the behavior of the base. Defining a Derived Class In our bookstore application, we will derive Bulk_item from Item_base, so Bulk_item will inherit the book, isbn, and price members. Bulk_item must redefine its _price function and define the data members needed for that operation: // discount kicks in when a specified number of copies of same book are sold // the discount is expressed as a fraction used to reduce the normal price class Bulk_item : public Item_base { public: // redefines base version so as to implement bulk purchase discount policy double _price(std::size_t) const。ll see, a derivation list might name more than one base class. Inheritance from a single base class is most mon and is the topic of this chapter. We39。 // ok: uses price from a Bulk_item object ret = 。b) { // attempt to use protected member double ret = price。s assume that Bulk_item defines a member function that takes a reference to a Bulk_item object and a reference to an Item_base object. This function may access the protected members of its own object as well as those of its Bulk_item parameter. However, it has no special access to the protected members in its Item_base parameter: void Bulk_item::memf(const Bulk_item amp。 For the most part, this class looks like others we have seen. It defines a constructor along with the functions we have already described. That constructor uses default arguments (Section , p. 253), which allows it to be called with zero, one, or two arguments. It initializes the data members from these arguments. The new parts are the protected access label and the use of the virtual keyword on the destructor and the _price function. We39。 // identifier for the item protected: double price。 } // returns total sales price for a specified number of items // derived classes will override and apply different discount algorithms virtual double _price(std::size_t n) const { return n * price。s work is trivial: It prints the results of calling book and _price on its item parameter. There are two interesting things about this function. First, even though its second parameter is a reference to Item_base, we can pass either an Item_base object or a Bulk_item object to this function. Second, because the parameter is a reference and the _price function is virtual, the call to _price will be resolved at run time. The version of _price that is called will depend on the type of the argument passed to print_total. When the argument to print_total is a Bulk_item, the version of _price that is run will be the one defined in Bulk_item that applies a discount. If the argument is an Item_base object, then the call will be to the version defined by Item_base. C++, dynamic binding happens when a virtual function is called through a reference (or a pointer) to a base class. The fact that