Section 15.6. Pure Virtual Functions


15.6. Pure Virtual Functions

The Disc_item class that we wrote on page 583 presents an interesting problem: That class inherits the net_price function from Item_base but does not redefine it. We didn't redefine net_price because there is no meaning to ascribe to that function for the Disc_item class. A Disc_item doesn't correspond to any discount strategy in our application. This class exists solely for other classes to inherit from it.

We don't intend for users to define Disc_item objects. Instead, Disc_item objects should exist only as part of an object of a type derived from Disc_item. However, as defined, there is nothing that prevents users from defining a plain Disc_item object. That leaves open the question of what would happen if a user did create a Disc_item and invoked net_price function on it. We now know from the scope discussion in the previous section that the effect would be to call the net_price function inherited from Item_base, which generates the undiscounted price.

Exercises Section 15.5.4

Exercise 15.24:

Why is it that, given

      Bulk_item bulk;      Item_base item(bulk);      Item_base *p = &bulk; 

the expression

      p->net_price(10); 

invokes the Bulk_item instance of net_price, whereas

      item.net_price(10); 

invokes the Item_base instance?

Exercise 15.25:

Assume Derived inherits from Base and that Base defines each of the following functions as virtual. Assuming Derived intends to define its own version of the virtual, determine which declarations in Derived are in error and specify what's wrong.

      (a) Base* Base::copy(Base*);          Base* Derived::copy(Derived*);      (b) Base* Base::copy(Base*);          Derived* Derived::copy(Base*);      (c) ostream& Base::print(int, ostream&=cout);          ostream& Derived::print(int, ostream&);      (d) void Base::eval() const;          void Derived::eval(); 


It's hard to say what behavior users might expect from calling net_price on a Disc_item. The real problem is that we'd rather they couldn't create such objects at all. We can enforce this design intent and correctly indicate that there is no meaning for the Disc_item version of net_price by making net_price a pure virtual function. A pure virtual function is specified by writing = 0 after the function parameter list:

      class Disc_item : public Item_base {      public:          double net_price(std::size_t) const = 0;      }; 

Defining a virtual as pure indicates that the function provides an interface for sub-sequent types to override but that the version in this class will never be called. As importantly, users will not be able to create objects of type Disc_item.

An attempt to create an object of an abstract base class is a compile-time error:

      // Disc_item declares pure virtual functions      Disc_item discounted; // error: can't define a Disc_item object      Bulk_item bulk;       // ok: Disc_item subobject within Bulk_item 

A class containing (or inheriting) one or more pure virtual functions is an abstract base class. We may not create objects of an abstract type except as parts of objects of classes derived from the abstract base.



Exercises Section 15.6

Exercise 15.26:

Make your version of the Disc_item class an abstract class.

Exercise 15.27:

Try to define an object of type Disc_item and see what errors you get from the compiler.




C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net