Inheritance and polymorphism
============================



Object-orientation == Classes + Inheritance
Inheritance is a fundamental technique for re-using existing code.



Let suppose we want to implement a software for MOT-like exams.
There are cars, trucks, buses, and they require different exams.


Let start it. Of course, we program in object-oriented way, so
we create a class for vehicles. There will be a constructor and
the mot() function for the exam itself.



class Vehicles
{
public:
  Vehicle( std::string pl );  // constructor
  bool mot() const;           // the exam itself

  // Further Vehicle interface ...
  std::string plate() const { _plate; }

private:
  std::string _plate;  // licence plate
  // Further Vehicle attributes ...

};



All vehicles have a mandatory attribute: the licence plate.
Further attributes are the pollution (for cars), lentgh and
the maximal number of passangers (for buses) and the total
weight and the number of axles (for trucks).

The problem is that some of the attributes valid only for some
kind of objects, e.g. axles are not interesting for buses.

Also mot() is full of conditions:



bool Vehicle::mot() const
{
  if ( this object is a Car )
    // evaluate Car-specific tests
  else if ( this object is a Bus )
    // evaluate Bus-specific tests
  else if ( this object is a Truck )
    // evaluate Truck-specific tests
}



This is a maintenance nightmare.

Perhaps it would be better to create separate classes for cars, buses,
trucks, ...  But we still want to keep common attributes and methods in
the same place.




class Car
{
public:
  // Interface for cars
private:
  Vehicle _veh; // common attributes for all vehicles
  // Car specific parts
};

class Truck
{
public:
  // Interface for trucks
private:
  Vehicle _veh; // common attributes for all vehicles
  // Truck specific parts
};




The problem is, that the Vehicle is not part of the Car/Truck interface:



class Car
{
public:
  // ...
  // Lots of boilerplate code for forwarding Vehicle interface
  std::string plate() { return _veh._plate; }

private:
  Vehicle _veh; // common attributes for all vehicles
  // Car specific parts
};




Inheritance
===========



                      ___________
                      |         |
                      | Vehicle |
                      |_________|
                           ^
                           |
             ______________|_______________
            |              |               |
       _____|_____    _____|_____     _____|_____
       |         |    |         |     |         |
       |   Car   |    |   Bus   |     |  Truck  |
       |_________|    |_________|     |_________|





//
// vehicle.h
//
#ifndef VEHICLE_H
#define VEHICLE_H

#include <string>

class Vehicle
{
public:
  Vehicle( std::string pl) : _plate(pl) {}

  bool mot() const;
  std::string plate() const { return _plate; }

  bool brakes() const { return true; }  // simulation
  bool lights() const { return true; }  // simulation

private:
  std::string _plate;
};

inline bool Vehicle::mot() const { return brakes() && lights(); }

#endif /* VEHICLE_H */




//
// car.h
//
#ifndef CAR_H
#define CAR_H

#include <string>
#include "vehicle.h"

class Car : public Vehicle
{
public:
  Car( std::string pl, int emis) : Vehicle(pl), _emis(emis) {}

  bool mot() const {
                     return Vehicle::mot()
                            && _emis < 130; // grams/km
                   }

  int emission () const { return _emis; }

private:
  int _emis; // grams/km CO2 emission
};

#endif /* CAR_H */



//
// bus.h
//
#ifndef BUS_H
#define BUS_H

#include <string>
#include "vehicle.h"

class Bus : public Vehicle
{
public:
  Bus( std::string pl, int len, int pers) : Vehicle(pl),
                                            _length(len),
                                            _persons(pers) {}
  bool mot() const {
                     return Vehicle::mot()
                            && _persons/_length < 4;
                   }

  int length() const { return _length; }
  int person() const { return _persons; }

private:
  int _length;  // total length
  int _persons; // max persons carried
};

#endif /* BUS_H */



//
// truck.h
//
#ifndef TRUCK_H
#define TRUCK_H

#include <string>
#include "vehicle.h"

class Truck : public Vehicle
{
public:
  Truck( std::string pl, int tw, int al) : Vehicle(pl),
                                           _totalWeight(tw),
                                           _axles(al) {}

  bool mot() const {
                     return Vehicle::mot()
                            && _totalWeight/_axles < 5000.;
                   }

  int totalWeight() const { return _totalWeight; }
  int axles() const { return _axles; }

private:
  int _totalWeight;  // kg
  int _axles;        // number of
};

#endif /* TRUCK_H */





There is 3 kind of inheritance in C++
=====================================



public:
  This is the "classical" inheritance. The base class public interface
  "extends" the derived class interface. This is the inheritance in OO.

protected:
  The public part of the base class is visible in all derived classes of
  teh derived class in transitive way.

private:
  The public part of the base class is not visible outside of the
  derived class. This is "inheritance for implementation".



class MyStream : private boost::noncopyable
{
  // a class we do not want to copy
  // inherits private copy operations from boost library
};




In the derived classes we have to provide the parameters for the
base class constructors:



  Truck::Truck( std::string pl, int tw, int al) :
        Vehicle(pl),      // base constructor
        _totalWeight(tw), // attributes
        _axles(al)        // attributes
  {
     // constructor body
  }




The construction order of subobjects is (in recursive way):

1. base classes (in order of declaration)
2. attrinutes (in order of declaration)
3. run of the constructor body


Destruction order (in destructors) is the opposite.



Multiply inheritance also exists in C++





Relation between base and derived objects
=========================================



"Liskov Substitutional Principle":

If "S" is a subtype of "T", then objects of type "T" may be replaced
with objects of type "S" (i.e., objects of type "S" may substitute
objects of type "T") without altering any of the desirable properties
of that program.




  Vehice v, *vp = &v;   // base object and pointer
  Car    c, *cp = &c;   // derived object and pointer
  Truck  t, *tp = &t;   // derived object and pointer



  // upcast: 

   v = c;       // ok, slicing, derived information will be lost

  vp = cp;      // ok, pointer will point to derived object

  vp == cp      // derived pointer will be equal to base pointer

  (void*)vp ?:= (void*)cp // but they not necessary point to the same memory

  Vehicle &vr = c;  // ok, vr references to the base part of derived object



  // downcast: not working by default, one should use cast operations.

   c = v;       // syntax error

  cp = vp;      // syntax error, vp may points to a Truck

  // valid if Vehicle polymorphic  
  if ( cp = dynamic_cast<Car*>(vp) )    // run-time check

  Car &cr = dynamic_cast<Car&>(vr);     // may throw std::bad_cast





Try to put it together
======================



/* 
 * MOT exam 
 */

#include <iostream>
#include <string>
#include <list>

#include "vehicle.h"
#include "car.h"
#include "bus.h"
#include "truck.h"


int main()
{
  std::list<Vehicle*>  waitlist;

  waitlist.push_back(new Car("AAA-111", 120) );
  waitlist.push_back(new Car("AAA-222", 140) );
  waitlist.push_back(new Bus("BBB-333", 20, 85) );
  waitlist.push_back(new Bus("BBB-444", 15, 55) );
  waitlist.push_back(new Truck("TTT-555", 12000, 2) );
  waitlist.push_back(new Truck("TTT-666", 14000, 3) );

  for ( std::list<Vehicle*>::const_iterator i = waitlist.begin();
                                            i != waitlist.end();
                                            ++i )
  {
    bool result = (*i)->mot();  // calls Vehicle::mot()
    std::cout << (*i)->plate() << ", mot exam "
              << (result ? "passed" : "failed")
              << std::endl;
  }

  // objects should have been deleted

  return 0;
}



The problem is, that we refer to the derived objects with a base pointer.
The compiler thinks the pointed object as Vehicle (instead of Car or Bus).

"Static type": the type known compile-time. Type checking is done against it.
"Dynamic type": the real type of the object, we know it only in run-time.

How can we call Car::mot(), Bus::mot() instead of Vehicle::mot() ?:



First we try to use dynamic_cast, as part of RTTI.
RTTI == RunTimeTypeIdentification.
We should insert at least one virtual function to Vehicle to enable



#include <iostream>
#include <string>
#include <list>

#include "vehicle.h"
#include "car.h"
#include "bus.h"
#include "truck.h"


int main()
{
  std::list<Vehicle*>  waitlist;

  waitlist.push_back(new Car("AAA-111", 120) );
  waitlist.push_back(new Car("AAA-222", 140) );
  waitlist.push_back(new Bus("BBB-333", 20, 85) );
  waitlist.push_back(new Bus("BBB-444", 15, 55) );
  waitlist.push_back(new Truck("TTT-555", 12000, 2) );
  waitlist.push_back(new Truck("TTT-666", 14000, 3) );

  for ( std::list<Vehicle*>::const_iterator i = waitlist.begin();
                                            i != waitlist.end();
                                            ++i )
  {
    bool result = false;
    // bool result = (*i)->mot();
    if ( Car *cp = dynamic_cast<Car*>(*i) )
    {
      result = cp->mot();
    }
    else if ( Bus *bp = dynamic_cast<Bus*>(*i) )
    {
      result = bp->mot();
    }
    else if ( Truck *tp = dynamic_cast<Truck*>(*i) )
    {
      result = tp->mot();
    }
    else
    {
      result = false; // unknown vehicle type
    }
    std::cout << (*i)->plate() << ", mot exam "
              << (result ? "passed" : "failed")
              << std::endl;
  }
  // objects should have been deleted

  return 0;
}



$ g++ -ansi -W -Wall mot-main.cpp
$ ./a.out
AAA-111, mot exam passed
AAA-222, mot exam failed
BBB-333, mot exam failed
BBB-444, mot exam passed
TTT-555, mot exam failed
TTT-666, mot exam passed



Works fine, but ...


  1. Hard to maintain:

     Every time a new type of vehicle appears, we have to insert a new branch.
     Perhaps in many different places.

  2. Not precise:

     The dynamic_cast<Truck*> converts to Truck pointer. Even if the
     real object is derived from truck, like class Lorry.




Polymorphism
============



In theory: we send a message to the object, and the reaction may depend
on the (dynamic) type of the object.


In some languages methods are virtual by default, in C++ they are not.


In C++: virtual methods may have "overriding" versions in derived classes.
Calling the function on the real object executes the overriding version
corresponding the dynamic type of the object.





/*
 *
 * Vehicle - base clas
 */

#ifndef VEHICLE_H
#define VEHICLE_H

#include <string>

class Vehicle
{
public:
  Vehicle( std::string pl) : _plate(pl) {}

  virtual bool mot() const;

  std::string plate() const { return _plate; }

  bool brakes() const { return true; }  // simulation
  bool lights() const { return true; }  // simulation

private:
  std::string _plate;
};

inline bool Vehicle::mot() const { return brakes() && lights(); }

#endif /* VEHICLE_H */




In the derived classes, we "override" the mot() function.

We have to follow the signature the mot() declared in the base class.
Any small difference in the signature case "hiding" instead of overriding.

In C++11, the "override" specifier helps to detect such issues.



/*
 * Car
 */

#ifndef CAR_H
#define CAR_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Car : public Vehicle
{
public:
  Car( std::string pl, int emis) : Vehicle(pl),
                                   _emis(emis) {}

  virtual bool mot() const /* override */ {
                             return Vehicle::mot()
                                    && _emis < 130; // grams/km
                           }

  int emission () const { return _emis; }

private:
  int _emis; // grams/km CO2 emission
};

#endif /* CAR_H */




The virtual keyword in the derived classes is not mandatory
but very much suggested for documentational purposes.



/* 
 * Bus
 */

#ifndef BUS_H
#define BUS_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Bus : public Vehicle
{
public:
  Bus( std::string pl, int len, int pers) : Vehicle(pl),
                                            _length(len),
                                            _persons(pers) {}

  virtual bool mot() const {
                             return Vehicle::mot()
                                    && _persons/_length < 4;
                           }

  int length() const { return _length; }
  int person() const { return _persons; }

private:
  int _length;  // total length
  int _persons; // max persons carried
};

#endif /* BUS_H */




Calling virtual function by scope operator eliminate polymorphism.
Vehicle::mot() calls Vehicle::mot().



/* 
 * Truck
 */

#ifndef TRUCK_H
#define TRUCK_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Truck : public Vehicle
{
public:
  Truck( std::string pl, int tw, int al) : Vehicle(pl),
                                           _totalWeight(tw),
                                           _axles(al) {}

  virtual bool mot() const {
                             return Vehicle::mot()
                                    && _totalWeight/_axles < 5000.;
                           }

  int totalWeight() const { return _totalWeight; }
  int axles() const { return _axles; }

private:
  int _totalWeight;  // kg
  int _axles;        // number of
};

#endif /* TRUCK_H */




In the main() function we do not separate the different types.
It is important, that we use pointers (or references) to keep
the right dynamic type of the objects.



/* 
 * MOT exam 
 */

#include <iostream>
#include <string>
#include <list>

#include "vehicle.h"
#include "car.h"
#include "bus.h"
#include "truck.h"


int main()
{
  std::list<Vehicle*>  waitlist;

  waitlist.push_back(new Car("AAA-111", 120) );
  waitlist.push_back(new Car("AAA-222", 140) );
  waitlist.push_back(new Bus("BBB-333", 20, 85) );
  waitlist.push_back(new Bus("BBB-444", 15, 55) );
  waitlist.push_back(new Truck("TTT-555", 12000, 2) );
  waitlist.push_back(new Truck("TTT-666", 14000, 3) );

  for ( std::list<Vehicle*>::const_iterator i = waitlist.begin();
                                            i != waitlist.end();
                                            ++i )
  {
    bool result = (*i)->mot();  // virtual function called on dynamic type
    std::cout << (*i)->plate() << ", mot exam "  // non-virtual: call base
              << (result ? "passed" : "failed")
              << std::endl;
  }
  return 0;
}




$ g++ -ansi -W -Wall mot-main.cpp
$ ./a.out
AAA-111, mot exam passed
AAA-222, mot exam failed
BBB-333, mot exam failed
BBB-444, mot exam passed
TTT-555, mot exam failed
TTT-666, mot exam passed





A few items are still missing from the program.





Virtual destructor and cloning
==============================



We have to delete the created objects. We create different subtypes
of vehicle, but


    delete (*i);


would call Vehicle::~Vehicle(), the destructor of the base class.
The Vehicle destructor must be virtual!



There are no virtual constructor (or copy constractor).
But we can use the clone() pattern:




class Base
{
public:
  Base *clone() { return new Base(*this); }
  // ...
};




class Derived : public Base
{
public:
  Derived *clone() { return new Derived(*this); }
  // ...
};




int main()
{
  std::list<Vehicle*>  waitlist, donelist;

  waitlist.push_back(new Car("AAA-111", 120) );
  waitlist.push_back(new Car("AAA-222", 140) );
  waitlist.push_back(new Bus("BBB-333", 20, 85) );
  waitlist.push_back(new Bus("BBB-444", 15, 55) );
  waitlist.push_back(new Truck("TTT-555", 12000, 2) );
  waitlist.push_back(new Truck("TTT-666", 14000, 3) );

  for ( std::list<Vehicle*>::const_iterator i = waitlist.begin();
                                            i != waitlist.end();
                                            ++i )
  {
    donelist.push_back( (*i)->clone() );  // creates the right type 
  }                                       // and pushes to the list
}




Pure virtual and abstract classes
=================================



Vehicle should be "abstract" class: i.e. we do not want to create
Vehicle objects. To forbid instantiation and make overriding mandatory
we use "pure virtual" functions.



class Vehicle
{
public:
 Vehicle( std::string pl) : _plate(pl) {}
 virtual ~Vehicle() {}
 virtual Vehicle *clone() const = 0;    // pure virtual
 virtual bool mot() const = 0;          // pure virtual
 // ...

};

// pure virtual may be implemented (but only outside of class).
inline bool Vehicle::mot() const { return brakes() && lights(); }





Factory functions
=================



How to create the subobjects dynamically?:



class Car
{
public:
  // ...
  static Car *create ()
  {
    std::string plate;
    int emis;

    std::cout << "Give Car data ( plate emission ) :";
    std::cin >> plate >> emis;

    return new Car(plate, emis);
  }

};



Such functions are called "Factory" functions.


The static functions are normal global functions, just organized into
the namespace of the class. Such functions have access to all class members.






The final version
=================





/*
 *
 * Vehicle - base clas
 */

#ifndef VEHICLE_H
#define VEHICLE_H

#include <string>

class Vehicle
{
public:
  Vehicle( std::string pl) : _plate(pl) {}
  virtual ~Vehicle() {}

  virtual Vehicle *clone() const = 0;

  virtual bool mot() const = 0;

  std::string plate() const { return _plate; }

  bool brakes() const { return true; }  // simulation
  bool lights() const { return true; }  // simulation

private:
  std::string _plate;
};

inline bool Vehicle::mot() const { return brakes() && lights(); }

#endif /* VEHICLE_H */





/*
 * Car
 */

#ifndef CAR_H
#define CAR_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Car : public Vehicle
{
public:
  Car( std::string pl, int emis) : Vehicle(pl),
                                   _emis(emis) {}
  virtual ~Car() { std::cout << "Deleted car: " << plate() << std::endl; }

  virtual Car *clone() const { return new Car(*this); }

  static Car *create ()
  {
    std::string plate;
    int emis;

    std::cout << "Give Car data ( plate emission ) :";
    std::cin >> plate >> emis;

    return new Car(plate, emis);
  }

  virtual bool mot() const {
                             return Vehicle::mot()
                                    && _emis < 130; // grams/km
                           }

  int emission () const { return _emis; }

private:
  int _emis; // grams/km CO2 emission
};

#endif /* CAR_H */






/* 
 * Bus
 */

#ifndef BUS_H
#define BUS_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Bus : public Vehicle
{
public:
  Bus( std::string pl, int len, int pers) : Vehicle(pl),
                                            _length(len),
                                            _persons(pers) {}
  virtual ~Bus() { std::cout << "Deleted bus: " << plate() << std::endl; }

  virtual Bus *clone() const { return new Bus(*this); }

  static Bus *create()
  {
    std::string plate;
    int length, persons;

    std::cout << "Give Bus data ( plate legth persons ) :";
    std::cin >> plate >> length >> persons;

    return new Bus( plate, length, persons);
  }

  virtual bool mot() const {
                             return Vehicle::mot()
                                    && _persons/_length < 4;
                           }

  int length() const { return _length; }
  int person() const { return _persons; }

private:
  int _length;  // total length
  int _persons; // max persons carried
};

#endif /* BUS_H */






/* 
 * Truck
 */

#ifndef TRUCK_H
#define TRUCK_H

#include <string>
#include <iostream>
#include "vehicle.h"

class Truck : public Vehicle
{
public:
  Truck( std::string pl, int tw, int al) : Vehicle(pl),
                                           _totalWeight(tw),
                                           _axles(al) {}
  virtual ~Truck() { std::cout << "Deleted truck: " << plate() << std::endl; }

  virtual Truck *clone() const { return new Truck(*this); }

  static Truck *create()
  {
    std::string plate;
    double      totalWeight;
    int         axles;

    std::cout << "Give Truck data ( plate totalWeigth NumofAxles ): ";
    std::cin >> plate >> totalWeight >> axles;

    return new Truck( plate, totalWeight, axles);
  }

  virtual bool mot() const {
                             return Vehicle::mot()
                                    && _totalWeight/_axles < 5000.;
                           }

  int totalWeight() const { return _totalWeight; }
  int axles() const { return _axles; }

private:
  int _totalWeight;  // kg
  int _axles;        // number of
};

#endif /* TRUCK_H */








/* 
 * MOT exam 
 */

#include <iostream>
#include <string>
#include <list>

#include "vehicle.h"
#include "car.h"
#include "bus.h"
#include "truck.h"

void generateVehicles( std::list<Vehicle*>& l);
void removeVehicles( std::list<Vehicle*>& l);

int main()
{
  std::list<Vehicle*>  waitlist, donelist;

  generateVehicles( waitlist);

  for ( std::list<Vehicle*>::const_iterator i = waitlist.begin();
                                            i != waitlist.end();
                                            ++i )
  {
    bool result = (*i)->mot();  // virtual function call
    std::cout << (*i)->plate() << ", mot exam "
              << (result ? "passed" : "failed")
              << std::endl;

    donelist.push_back( (*i)->clone() );  // clone the list
  }

  removeVehicles( waitlist); // remove the original objects 
  removeVehicles( donelist); // remove the clones

  return 0;
}


void generateVehicles( std::list<Vehicle*>& l)
{
  char ch;
  std::cout << "Choose vehicle type: b(us), c(ar), t(ruck): ";
  while ( std::cin >> ch )
  {
    switch(ch)
    {
      case 'b' : l.push_back(Bus::create());   break;
      case 'c' : l.push_back(Car::create());   break;
      case 't' : l.push_back(Truck::create()); break;
      default  : break;
    }
    std::cout << "Choose vehicle type: b(us), c(ar), t(ruck): ";
  }
  std::cout << std::endl;
}

void removeVehicles( std::list<Vehicle*>& l)
{
    for ( std::list<Vehicle*>::const_iterator i = l.begin();
                                              i != l.end();
                                              ++i )
    {
      delete (*i);   // calls virtual destructor
    }
}



$ g++ -ansi -W -Wall mot-main.cpp

$ cat mot-input.txt
c AAA-111 120
c AAA-222 140
b BBB-333 20 85
b BBB-444 15 55
t TTT-555 12000. 2
t TTT-666 14000. 3

$ ./a.out < mot-input.txt
...
AAA-111, mot exam passed
AAA-222, mot exam failed
BBB-333, mot exam failed
BBB-444, mot exam passed
TTT-555, mot exam failed
TTT-666, mot exam passed
Deleted car: AAA-111
Deleted car: AAA-222
Deleted bus: BBB-333
Deleted bus: BBB-444
Deleted truck: TTT-555
Deleted truck: TTT-666
Deleted car: AAA-111
Deleted car: AAA-222
Deleted bus: BBB-333
Deleted bus: BBB-444
Deleted truck: TTT-555
Deleted truck: TTT-666




If we want to add new vehicle types, we just

  1. create the new class, implement the functions.
  2. implement the create() factory.
  3. override the virtual destructor, clone(), mot() functions.
  4. add just a line to generateVehicles().