6.9.1. Exercises: Containers of Pointers

  1. Suppose you need to write an inventory control system for automobile parts.

    • Write a UML class diagram with a base class named AutoPart and some subclasses like, EnginePart, BodyPart, Accessory, etc. and concrete part classes like Alternator, Fender, Radiator, SeatBelt, etc.

    • Write (but do not implement) class definitions for your classes. What kinds of base class functions will be needed?

    • How will you guarantee that only the concrete part classes can be instantiated?

  2. Figure 6.7.  Film classes

    Film classes

    The classes in Figure 6.7 are intended to help organize the film collection in the college library.

    1. Implement the Film classes. Make sure that the constructors have sufficient parameters to initialize all data members. We suggest enum types FilmTypes (Action, Comedy, SciFi, ...) and MPAARatings (G, PG, PG-13, ...) for use in the Entertainment class.

    2. Implement the FilmList class as a container of Film pointers. Make sure that the addFilm() function does not permit the same Film to be added more than once.

      Is it possible to use base class functions such as contains() or indexOf() here?

    3. Write client code to test these classes. Put a mixture of Entertainment and Educational films into the FilmList and exercise all the member functions.

    Having a container of pointers raises the question of how to destroy it. If you simply "do the right thing" and define a FilmList destructor that visits each of its pointers and deletes it, you must then worry about client code that contains a function with a FilmList value parameter. Recall that each value parameter causes a copy of the corresponding argument to be made. That copy is destroyed when the function returns. How should you deal with copying and destroying FilmList objects?

    The FilmList class enables you to exploit polymorphism but exposes the Film pointers to client code. So far, this design violates our earlier warning regarding the use of pointers. In general, pointers must be hidden from client code. We discuss an approach to this problem in Section 16.3.

  3. Refine our solution to Extended Example: A Simple Library by adding a LibraryUI class that handles the interactions with the user as suggested by the following UML diagram.

    Figure 6.8. Library - Version 2

    Library - Version 2

    When you add that class, you should use the client code in Example 6.43 to test your system.

    Example 6.43. src/pointer-container/libraryClient-v2.cpp

    #include "libraryui.h"
    #include "library.h"
    
    bool saved(false);
    
    int main() {
       Library lib;
       LibraryUI libui(&lib);
       while(1) {
          switch(libui.nextTask()) {
          case LibraryUI::READ: libui.read();
             saved = false;
             break;
          case LibraryUI::ADD: libui.enterData();
             saved = false;
             break;
          case LibraryUI::FIND: libui.find();
             break;
          case LibraryUI::REMOVE: libui.remove();
             saved = false;
             break;
          case LibraryUI::SAVE: libui.save();
             saved = true;
             break;
          case LibraryUI::LIST: libui.list();
             break;
          case LibraryUI::QUIT: libui.prepareToQuit(saved);
             break;
          default:
             break;
          }
       }
    }
    
    

  4. Refine your solution to 3 so that each class has its own corresponding UI class, as suggested by the following UML diagram.

    Figure 6.9. Library - Version 3

    Library - Version 3

  5. Change the implementation of the Library class so that it is derived from QMap<QString, RefItem*> where the QString key is the ISBN code.

[ fromfile: inheritance-intro.xml id: ex-inheritance ]