NOTE: This file has been broken into two files named generic-types.html and inheritance.html.

Inheritance Issues

I. Multiple Inheritance

    A. What it is: Inheriting from multiple classes

    B. Why use it

        1. You want to provide more than one view of an object

	    Example: A part may store both accounting and inventory 
	      information. The accounting system will want the part
	      to provide a different set of services (i.e., methods)
	      than the inventory system.

	      class part : public accounting, public inventory {

	      part widget = new part();
	      accounting *accountingWidget = part;
	      inventory *inventoryWidget = part;

	2. You want to inherit implementation from more than one class

	    Example: We want our administrative computing system to keep
	      all students of the same year (freshmen, sophomores, juniors,
	      seniors, etc) on some list. We may then want to inherit
	      both from a base class for people at the university, such
	      as person, and from a base class for linked lists.

    C. Problems with multiple inheritance

        1. What to do with duplicated names

	    a. duplicated instance variables can be referenced by prefixing
	       the variable name with the class name


	       class fruit {
	         int calories;
		 void debug_print() { printf("fruit cals = %d\n", calories); }

	       class veggie {
	         int calories;
		 void debug_print() { printf("veggie cals = %d\n", calories); }

	       class food : public fruit, public veggie {
	         food(int fcals, int vcals) {
		     fruit::calories = fcals;
		     veggie::calories = vcals;
		 void print_fields() {
		     printf("fruit calories = %d\n", fruit::calories);
		     printf("veggie calories = %d\n", veggie::calories);
		 void food::debug_print() {

	    b. duplicated method names can also be referenced by prefixing
	       the method name with the class name

	       i. What happens when an outside function tries to call
	          a duplicated method name? -- The derived class must
		  provide its own definition of the method

		  Example: see above

	      ii. The derived class can provide access to the duplicated
	          methods individually by providing new methods


		     void fruit_debug () { fruit::debug_print(); }
		     void veggie_debug () { veggie::debug_print(); }

	    c. duplicated names that are virtual methods--suppose we want
	         to override a virtual method from one of the base classes
		 (e.g., the part class wants to provide a different 
		 implementation for the accounting class's cost method).

		 i. we need to interpose an "interface" class between the
		    base class and the derived class

		    class part_interface : public accounting {
		        virtual void accounting_part_cost () = 0;
			void cost () { accounting_part_cost(); }

		    class part : public accounting, public inventory {
		        void accounting_part_cost { 
			   ... code to implement accounting's virtual
			       cost method ...

		    accounting *partWidget = new part();
		    partWidget->cost(); // calls the cost method in 
		                        // part_interface, which calls the
					// accounting_part_cost method in
					// part that overrides the cost
					// method

        2. Problems with multiple inheritance from the same base class: Should
	   an instance of the derived class contain one or two copies of
	   the base class?

	   Example:  class student_prof : public student, public professor {

           Desired Inheritance: probably want a student who is also a
	      professor to have only one instance of the person object
	      (one university id, name, etc) but two instances of the
	      list object, since you may want to link the professor to
	      a non-matriculated student list and to some faculty list

	   Inheritance Hierarchy:     list    person      list
                                        \      /  \        /
					 \    /    \      /
					  \  /      \    /
					student   professor
					   \          /
					    \        /
					     \      /

           a. Two types of inheritance

	       i. replicated inheritance: inherit separate copies from each
	          chain of the inheritance hierarchy (e.g., the inheritance
		  of the list object)

	      ii. shared inheritance: inherit a single copy from both branches
	          of the tree (e.g., the inheritance of the person object)

	   b. Replicated inheritance is the default in C++

	   c. Shared inheritance can be obtained by specifying that a
	       base class is virtual

	       class student : public virtual person, public list { ... }
	       class professor : public virtual person, public list { ... }

        3. Multiple inheritance also introduces implementation problems
	   for the compiler which are not discussed in this class

II. Mix-In Inheritance (Composition Versus Inheritance): Inheritance from
    one "real" base class and an arbitrary number of interfaces

    A. Ways to do it

        1. C++: Make the interfaces be abstract base classes with every
	    method in the base class declared as pure virtual.

        2. Java: Use interfaces 

    B. But suppose I want to

        1) inherit behavior from multiple classes, or
	2) inherit an object's behavior but not its interface

        1. Use composition: Make your class contain an object of the type
	    whose behavior you want to inherit

	    a. Have your methods call the corresponding methods in the
	       composed object

	       Example: class Rectangle {
	                    public void setWidth(int w) { ... }
			    public void setHeight(int h) { ... }
			    public int getArea() { ... }
			    public int getWidth() { ... }
			    public int getHeight() { ... }
			    public void draw() { ... }
			    public boolean pointInObject(int x, int y) { ... }

			    int width;
			    int height;

			class Square {
			  Rectangle mySquare;

			  public int getArea { return mySquare.getArea(); }
			  public void draw { mySquare.draw(); }
			  public boolean pointInObject(int x, int y) {
			      return mySquare.pointInObject(x, y); }
			  pubic void setSize(int s) { 
			  int getSize() { return mySquare.getWidth(); }

   	2. Composition works if you can get by with using the services that
	   an object provides, but sometimes you actually need access to its
	   internal implementation. 

	   a. Example: There is no way to store a List object in a student
	      class and achieve a threading of students. The only way to
	      do it is to inherit a List's implementation so that your program
	      can access the next fields.

	      Note: A better way to thread the students is to have a list
	         object completely outside the student class that holds the
		 students. That way a student can be on more than one list.
		 This example illustrates that often a small change to the
		 design can eliminate the need to inherit.

           b. In C++ one can use access modifiers before the base class to
	      control whether interface or implementation is inherited, or

	    a. class derived : public base { ... } -- inherits both the
	        interface and the implementation of the base class

	    b. class derived : protected base { ... } -- inherits the
	        implementation but not the interface of the base class

		i. all public methods in the base class become protected
		   methods in the derived class

	       ii. the using keyword can re-declare a method to be

	       Example: class Rectangle {
			    void setWidth(int w);
			    void setHeight(int h);
			    int getArea();
			    int getWidth();
			    int getHeight();
			    void draw();
			    bool pointInObject(int x, int y);
			    int width;
			    int height;

			class Square : protected Rectangle {
			    using Rectangle::getArea;
			    using Rectangle::draw;
			    using Rectangle::pointInObject;
			    void setSize(int s) { width = s; height = s; }
			    int getSize() { return width; }

III. Generic Types

    A. Polymorphism: refers to the ability of the same code to perform the
        same action on different types of data

	1. Inheritance supports one type of polymorphism: different methods
	    with the same name can perform the same type of action 
	    (e.g., draw an object, indicate whether a point lies in an object)

        2. True polymorphism means that the same code can be re-used
	    with different types of data.

	    Example: The code for a linked list is typically the same,
	      regardless of what type of object it is storing

    B. Traditional typed languages, such as C, C++, and Java, do not easily
       support true polymorphism, because functions must take parameters
       of a particular type and return values of a particular type. 
       However, all three languages provide ways to approximate it.

       1. Java provides the implicit master class Object. 

           a. Generic code uses the type Object whenever it needs to refer 
	      to a specific piece of data

	   b. Programs downcast the Object type to a specific type when they
	      retrieve an object from a generic data structure

	   c. Disadvantages

	       i. downcasting can be dangerous

	       ii. Object supports generic data structures but not generic
	           algorithms, such as quicksort, which require a common
		   comparator method

           d. Advantages: One copy of the code works with multiple types

        2. C++ provides templates

	   a. Disadvantages

	       i. the code is very complicated to write, to debug, and to

	      ii. a copy of the code must be created for each different type

	   b. Advantages: Supports both generic data structures and generic
	3. C provides void *'s

	   a. The programmer can create generic data types by declaring values
	      to be of type "void *"      
	   b. The programmer can pass in type-specific functions (e.g.,
	      comparator functions) that take void *'s as parameters and
	      that downcast the void *'s to the appropriate type before
	      manipulating the data

	   c. Advantages

	       i. One copy of the code works with multiple objects
	       ii. The approach supports both generic data structures and
	           generic algorithms--Note that this approach cannot be used
		   to support generic algorithms in Java since functions cannot
		   be passed as pointers

	   d. Disadvantages

	       i. Downcasting can be dangerous, even more so than in Java,
	          since run-time type checks are not performed in C

	      ii. The code often has a cluttered appearance (note how your
	          jval code looks)
    3. Both Java and C++ provide a set of generic data structures. 

        a. C++ provides the standard template library (STL), which includes
	   both templates for common data structures, such as lists and
	   hash tables, as well as common algorithms, such as quicksort.

        b. Java provides a set of standard data structures, such as lists
	   and hash tables, in its java.util package.