Lecture Notes for Advanced Programming II

4 December 2001 - Polymorphism and Inheritance


  1. polymorphism - making the type system more flexible, but still safe

    1. casting - eliminates differences between types; int and float; destructive (lost precision) and complicated (casting between a double and a string)

    2. overloading - makes many types respond to the same operators; int, float, and string addition; semantically dubious (string multiplication) and complicated (string multiplication, conversions and the n-by-m problem)

    3. templates - abstracts away types when not important; the size of a T list; implementation problems (code bloat, funny rules), some type aspects are important (equal T values)

  2. subtype polymorphism - related types exhibit similar behaviors

    1. example - numbers

      1. there are many number types (natural, integer, rational, floating point, complex); they all respond to arithmetic operators

      2. casting and templates are not appropriate (information loss and type specific operators)

      3. overloading (without casting) is appropriate, but how should it be organized

    2. subtype polymorphism models the behavioral similarities among a set of related types

    3. general approach

      1. a parent class models the abstract, generic behavior of the related types as an abstract, generic type - for example, class Number

      2. each specific type is modeled as a child of the parent class - for example, class Integer : Number or class Complex : Number

      3. rule of thumb - the longest path from root to leaf should be short, two or three classes

        1. longer paths are complicated because information is spread out

    4. how does subtype polymorphism work - inheritance

      1. inheritance provides both prototype sharing and polymorphism

      2. parent prototypes are copied to the children - behavioral sharing

        1. "behavior" means behavior at the prototype, not code sharing

        2. defines the consistent behavior property among the related types

      3. polymorphism comes from the parent-child relation - is-a inheritance

        1. a child type is-a kind of parent type - an integer is a kind of number

        2. shared prototypes makes is-a inheritance useful - the child really is-a kind of parent

  3. recognizing subtype polymorphism

    1. it should be designed into the code

      1. reduces design effort - design the parent class once and the child classes follow along

      2. reduces coding effort - the parent-child relation neatly and clearly factors and emphasizes coding obligations

      3. increases syntactic clarity - the parent class sets the notation (operators) for all its children, rather than having notation specific to each child

      4. increases semantic clarity - a number is a number, and it gets added

    2. missed opportunities for subtype polymorphism smell like type-based if or case statements

      1. for example - from my solution to programming assignment 3

        1. an expression is a node; a node is one of three types: number, variable, or operation

          void expression::write(ostream & os) const {
            if (expr_t == operation) {
              left->write(os);
              os << " " << prep << " ";
              right->write(os);
              }
            else if (expr_t == number)
              val.write(os);
            else {
              assert(expr_t == variable)
              os << prep;
              }
            }
          

        2. define the parent class node and the children class number_node : node, class variable_node : node, and class operator_node : node

      2. for example - adapted from the text

        1. a student record can be for a graduate or undergraduate

          if (ch == 'u')
            record.type = undergrad;
            // read undergrad information
          else
            record.type = graduate;
            // read graduate information
          

        2. define a parent class record and children class grad_rec : record and class ugrad_rec : record

        3. the book does something slightly different and slightly less clean

  4. points to remember

    1. missed subtype polymorphism looks like type-based if or case statements

    2. design for subtype polymorphism

      1. what things behave similarly (have the same set of prototypes) - these are the child classes

      2. what is the common set of similar behaviors - this is the parent class

    3. use inheritance to share prototypes, not code - "behavior" means prototype, not code

      1. code-sharing inheritance was the oo tragedy of the '80s

      2. code-sharing inheritance hierarchies are narrow, brittle, and complex

      3. break this rule only under subtype polymorphism

        1. factor common code from the children into the parent

        2. don't force parent code on the children


This page last modified on 4 December 2001.