Inheritance

   ------------------------
   |  |----------|        |
   |  |  base    |        |
   |  |  class   |        |
   |  |----------|        |
   |                      |
   |    derived class     |
   |                      |
   ------------------------

Three types of inheritance:

  1. public
  2. private
  3. protected

Public Inheritance

A member of the derived class
     is a
(or is a kind of)
the base class.

Anything that may be done to a member
of the base class may be done to
a member of the derived class
(but not the other way around).


In Java

   class Derived extends Base {

   }

In C++

   class Derived : public Base {

   }

Most of the declaration

class Base {
  public:
    Base( );
    void doBase( );
  private:
    int bfield1;
}

class Derived: public Base {
  public:
    Derived( );
    void doDerived( );
  private:
    int dfield2;
}

   -----------------------------------
   |  |------------------------|     |
   |  |public:     private:    |     |
   |  |  Base()     int bfield1|     |
   |  |  doBase()              |     |
   |  |------------------------|     |
   |                                 |
   |   public:        private:       |
   |     Derived()     int dfield2   |
   |     doDerived()                 |
   |                                 |
   -----------------------------------

Partial code that shows a use:

  Base X;
  Derived Y;

  X.doBase()

  // shows inheritance: invoke 
  // base member function on derived object
  Y.doBase()    

  // invoke derived member function 
  // on derived object
  Y.doDerived() 

Making the derived class behave differently
than the base class

class Base {
  public:
    Base( );
    void doBase( );
    void doCommon( );
  private:
    int bfield1;
}

class Derived: public Base {
  public:
    Derived( );
    void doDerived( );
    void doCommon( );
  private:
    int dfield2;
}

Partial code to show use:

  Base X;
  Derived Y;

  X.doBase()
  X.doCommon()   // invokes Base::doCommon()

  // shows inheritance: invoke 
  // base member function on derived object
  Y.doBase()    
  Y.doCommon()   // invokes Derived::doCommon()

This is as we expect
(WRT which function is invoked).

But, if . . .

  Base X;
  Derived Y;

  Base & refX = X;
  Base & refY = Y;

  refX.doCommon()  // invokes Base::doCommon()

  refY.doCommon()  // invokes Base::doCommon()

The type of the reference determines
which class' function is invoked
for both references and pointers.


If we want the choice of doCommon() based on
what a pointer or reference refers to:

Use the key word virtual in the declaration.

class Base {
  public:
    virtual void doCommon( );
}

class Derived: public Base {
  public:
    virtual void doCommon( );
}

virtual in the derived class doCommon()
is irrelevant, and is included for clarity.
(Your code will also include it for clarity!)


Same code as before, with different behavior:

  Base X;
  Derived Y;

  Base & refX = X;
  Base & refY = Y;

  refX.doCommon()  // invokes Base::doCommon()

  refY.doCommon()  // invokes Derived::doCommon()

Virtual in the base class determines,
and is commonly declared virtual if a derived
class is likely to redefine a function.

Also, declare the destructor of the base class
as virtual, to cause calls to destructors
in the right order.


Static versus Dynamic Binding

Rules for which method gets invoked
(base or derived) under inheritance
were just given.

Rules for which method gets invoked
under function overloading depends
on the signature.

But, under both inheritance and function overloading,
which method gets invoked?


Java only does dynamic binding,
because its entire O.O. model is based on
inheritance from the base Object.

C++ uses static binding wherever possible.
Where not possible, it uses dynamic binding.

It is less efficient to run code that utilizes
dynamic binding!

This illustrates an overriding difference between
Java and C++:
Java always chooses programmer safety over
efficiency.
C++ always chooses efficiency.


Static Binding (also called early binding)

At compile time,
the compiler knows which method is to be invoked.

  Derived Y;

   Y.doCommon()  // known at compile time
                 // does Derived::doCommon()

Dynamic Binding

The choice cannot and is not made until run time
(execution time).

This happens when overloaded functions under
inheritance are declared virtual.

  Base X;
  Derived Y;

  Base & refX = X;
  Base & refY = Y;

  if ( wantBase )
    refY = refX;

  refY.doCommon()  // which one?

Upcasting
(a good term to know for understanding)

  Derived Y;
    Base & refBase = Y;

Upcasting is always OK.

We can always do Base-type things to Derived-type objects.


Downcasting
(also a good term to understand, but not
usually a good idea to include in a program)

  Base X;
  Derived Y;
  Base * pB = &Y;  // upcasting, and OK

  Derived * pD = (Derived *) X;  // downcasting
  pD->doDerived()  // might operate on derived
                   // data members, which *pD
                   // does not have!

Downcasting requires an explicit type cast,
because we want to force the programmer
to want the "unsafe" behavior.


Hiding

Redefinition under inheritance is
different and separate from overloading
using signatures to distinguish.

  class Base {
    public:
      virtual void doCommon(int);
  }
  class Derived {
    public:
      void doCommon();
  }

  Derived Y;
  Y.doCommon()   // does Derived::doCommon()
  Y.doCommon(6)  // ???

The derived class hides the base class.


To fix the hiding problem,

1. In the base class, define all possible signatures
that may appear in the derived class:

 class Base {
   public:
     virtual void doCommon();
     virtual void doCommon(int);
 }
 class Derived {
   public:
     void doCommon();    // having only one of these
     void doCommon(int); // would hide the other in 
 }                       // the base class

2. The derived definition can call the base one:

     doCommon {          // definition
       Base::doCommon(6)
     }

Not enough time to cover all 3 types of inheritance:

  1. public
  2. private
    Public and protected members of the base class
    become private members of the derived class.
  3. protected
    Affects the access for a derived class.
    Members of the derived class can access protected
    members of the base class directly.

Other inheritance topics not covered:


Copyright © Karen Miller, 2007