(Latest Revision: Mon Sep 28 12:01 PDT 2015 ) C++_4_Notes01_Inheritance

C++ Interlude 4 Notes on Inheritance


Notes on the text of C++ Interlude 4 -- INHERITANCE

  X
   \
    \
      Y
A class Y that has been derived from a class X is all that X was, and more. Y has additional data and/or function members.

However, Y may have its own versions of some of X's members. In that case, the members of Y are the ones that are supposed to "respond."

For example if SoccerBall is a derived class of Sphere
  Sphere
     \
      \
     SoccerBall
and both classes have member functions (methods) called drawSelf then if I have a variable mySoccerBall of type SoccerBall and I make a call to mySoccerBall.drawSelf(), it will cause the version of drawSelf belonging to the SoccerBall class to be executed , and not the version of drawSelf derived from the Sphere class. (Presumably the result will be that the drawing will look more like a soccer ball and not like a plain sphere.)

Exception: A derived class inherits all the members of its base class, except the constructors and destructor.

The advantage of using inheritance is software reuse: you have less to program if you create a new class as a derived class of a pre-existing class. (Perhaps it is easier for people programming long-term in some particular application area to appreciate this advantage. )

For example, if you are using classes to model the acoustic properties of musical instruments, you could possibly save a lot of work by creating a class for a new instrument by treating it as a derived class of a preexisting instrument -- maybe like a new kind of horn being a derived class of horn -- all horns have some characteristics in common.

Note: Good documentation of the base class must be available. Otherwise programmers will not have enough information to know how to create derived classes.

This example of inheritance from a previous edition of the text:
 //THIS IS THE BASE CLASS (SPHERE)
class sphereClass
{
  private:
     double TheRadius;  // the sphere's radius

  public:

           /* constructors. */
     sphereClass(); 
     sphereClass(double InitialRadius); 

           /* copy constructor and destructor will be 
              supplied by the compiler */

           // sphere operations:
     void SetRadius(double NewRadius);
     double Radius() const;
     double Diameter() const;
     double Circumference() const;
     double Area() const;
     double Volume() const;
     void DisplayStatistics() const; 
};  // end class
Here is how the derived class is declared -- less work to do here because we get lots of "declarations" from the base class "for free"
const int MAX_STRING = 15;
class ballClass: public sphereClass

         /* The line above says that we want ballClass to be
            derived from sphereClass (publicly)*/
{
  private:
         /* this data member is a new one -- in addition to
            TheRadius, which we get from the parent class */
    char TheName[MAX_STRING+1];  // the ball's name  

  public:

     ballClass();  // default constructor

             /* Another constructor: Creates a ball with radius
                InitialRadius and name InitialName. */
     ballClass(double InitialRadius, const char InitialName[]); 

        /* copy constructor and destructor supplied
           by the compiler */

       /* It's important to notice what is NOT here:
          all the member functions of sphereClass 
          -- no need to re-declare -- we get all that 
          automatically. For example users will be able 
          to make calls like: ball.Volume() when ball 
          is an instance of ballClass (a variable of 
          type ballClass). */

       /* additional or revised operations: */

      /* this operation is new in the derived class
         Determines the name of a ball. */
     void GetName(char CurrentName[]) const;    

           /* this operation is new in the derived class
              Sets (alters) the name of an existing ball. */
     void SetName(const char NewName[]);  

          /* this operation is new in the derived class Sets
             (alters) the radius and name of an existing ball
             to NewRadius and NewName, respectively. */
     void ResetBall(double NewRadius, const char NewName[]);

          /* this operation is re-defined in the derived
             class.  It displays the statistics of a
             ball. */
     void DisplayStatistics() const;
};  // end class
Important characteristics:

The Keywords Public, Private and Protected

How They Determine Characteristics of Class Members
(Data Members or Member Functions)

Public, Private, and Protected Inheritance.

How The Keywords {Public, Private and Protected}
Determine Kinds of Inheritance:
Normally you would use public inheritance when you have an "is-A" relationship. A ball is a sphere, a kitchen is a room, and so on. Here every characteristic of the base class is also a characteristic of the derived class. Therefore when you give access to the derived class there is no reason to exclude access to the base class.

If the relationship is a "has-a" relationship but not a "is-a" relationship then do not use inheritance. Instead give one class an instance of another class as a data member. For example a ball-point pen has a ball, and a mammal has a heart. The class representing a ball-point pen could have a data member that is an instance of the ball class. A mammal class could be given a heart class data member.

Normally you would use private inheritance when you have a "as-a" relationship to represent. A stack can be thought of as a list of a certain kind. You can implement a stack by inheriting from a list class. However if you give access to the stack, you don't usually also want to give access to the list base class because that would allow the client to do things like insert an item into the bottom or the middle of the stack, which would violate its last-in-first-out structure.