Examples
Team LiB
Previous Section Next Section

Examples

Example: Drawing shapes. The classic example is drawing objects. A typical C-style, switch-on-type solution would define an enumerated member variable id_ for each shape that stores the type of that shape: rectangle, circle, and so on. Drawing code looks up the type and performs specific tasks:



class Shape {// …


  enum {RECTANGLE, TRIANGLE, CIRCLE }id_;





  void Draw() const {


   switch( id_ ) {                      // bad


   case RECTANGLE:


    // … rectangle drawing code …


    break;





   case TRIANGLE:


    // … triangle drawing code …


    break;





   case CIRCLE:


    // … circle drawing code …


    break;





   default:                             // bad


    assert( !"Oops, forgot to update this switch when adding a new Shape" ); 


    break;


   }


  }


};



Such code creaks under its own weight, fragility, rigidity, and complexity. In particular, it suffers from the dreaded transitive cyclic dependency mentioned in Item 22. The default branch is symptomatic of "don't know what to do with this type" syndrome. Contrast that with an implementation that you could pull from any OO text:



class Shape {// …


  virtual void Draw() const = 0;             // let each derived class implement it


};



Alternatively (or in addition), consider this implementation that follows the advice to make decisions at compile time where possible (see Item 64):



template<class S>


void Draw( const S& shape ) {


  shape.Draw();                         // might or might not be virtual;


};                                      // see Item 64



Now the responsibility of drawing each geometric figure goes to the figure implementation itselfand there's no more "can't handle this type" syndrome anymore.

    Team LiB
    Previous Section Next Section