Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Inheritance


Contents

Introduction

Object oriented programming should have other features besides the ability to bundle data members and methods and provide access specifiers. It should also have inheritance and polymorphism.

A class can be derived from from another class. Let's say we have a Person class. We can have an Employee class that is derived from it. The Employee class will inherit all the member data variables and the member functions from the Person class. Since an Employee class is derived from a Person class it is a Person class also. This is called upcasting. However a Person may not be an employee so we cannot downcast.

File: i1.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    string getName()
    {
        return ( firstName + " " + lastName ) ;
    }
};

class Employee : public Person
{
    public:
     string jobTitle ;
     void print()
     {
         cout << getName() << " " << jobTitle << endl ;
     }
};

int main()
{
    Employee e1  ;
    //Can access the base class variables
    e1.firstName = "Alan"  ;
    e1.lastName = "Turing"  ;
    e1.jobTitle = "Programmer" ;
    e1.print() ;
    Person p1 ;
    p1 = e1 ;
    //Can't do
    // e1 = p1 ;
    return 0 ;
}
In the above example we have a base class called "Person" and a derived class "Employee". An employee is a person but has more attributes; in this case "jobTitle". It can inherit the attributes and the member functions from the base class.
There is a new access specifier called "protected" . A protected data member can be seen by the derived class but not outside the derived class.

File: i2.cpp
class A1
{
    public:
     int x1 ;
    protected :
     int x2 ;
    private :
     int x3 ;
};

//B1 is derived from A1class

class B1 : public A1
{
    void method1()
    {
        x2 = 4 ;
        //A derived class can access
        //a protected member
        //Cannot access a private member of a base class
        //x3 = 5 ;

    }
};

int main()
{
    A1 A1Object ;
    B1 B1Object ;
    int c1 = A1Object.x1 ;
    //Access issue
    //c1 = A1Object.x2 ;
    //c1 = A1Object.x3 ;

    //ok x1 is public
    c1 = B1Object.x1 ;

    //Protected not accessible outside
    //c1 = B1Object.x2 ;

    //Private not accessible outside
    //c1 = B1Object.x3 ;
    return 0 ;
}
The "protected" scope is not visible outside the class but is visible to the derived class.

Exercise



1) Modify the firstName and lastName in the Person example above to be protected and "getName" to be public. Comment out the below 2 lines.
e1.firstName = "Alan" ; e1.lastName = "Turing" ;
Compile and run the program.

File: ex1.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    string getName()
    {
        return ( firstName + " " + lastName ) ;
    }
};

class Employee : public Person
{
    public:
     string jobTitle ;
     void print()
     {
         cout << getName() << " " << jobTitle << endl ;
     }
};

int main()
{
    Employee e1  ;
    //Can access the base class variables
    e1.firstName = "Alan"  ;
    e1.lastName = "Turing"  ;
    e1.jobTitle = "Programmer" ;
    e1.print() ;
    Person p1 ;
    p1 = e1 ;
    //Can't do
    // e1 = p1 ;
    return 0 ;
}
In addition to data members having access specifier we can specify an access specifier in the derived class and that tells us what the access ( modified ) would be in the derived class for the base class for someone looking at it from outside. One easy way to remember what the access means is to think of the access as it applies to the public and protected members of the base class. Public inheritance means that the public and protected members of the base class stay as it is. Protected inheritance means that the public and protected members of the base class become protected and private inheritance means the public and protected members of the base class become private.
The concept is somewhat confusing in the beginning and we need to look at some examples.

Public Inheritance



File: i3.cpp
class Base
{
    public:
    int m_public;
    private:
    int m_private;
    protected:
    int m_protected;
};

class Pub: public Base
// note: public inheritance
{
    // Public inheritance means:
    // Public inherited members stay public
    //(so m_public is treated as public)

    // Protected inherited members stay protected
    //(so m_protected is treated as protected)
    // Private inherited members stay inaccessible
    //(so m_private is inaccessible)
    public:
    Pub()
    {
        m_public = 1;
        // okay: m_public was inherited as public
        //m_private = 2;
        // not okay: m_private is inaccessible from derived class
        m_protected = 3;
        // okay: m_protected was inherited as protected
    }
};
int main()
{
    // Outside access uses the access specifiers of the
    //class being accessed.
    Base base;
    base.m_public = 1;
    // okay: m_public is public in Base
    //base.m_private = 2;
    // not okay: m_private is private in Base
    //base.m_protected = 3;
    // not okay: m_protected is protected in Base
    Pub pub;
    pub.m_public = 1;
    // okay: m_public is public in Pub
    //pub.m_private = 2;
    // not okay: m_private is inaccessible in Pub
    //pub.m_protected = 3;
    // not okay: m_protected is inaccessible in Pub
}

Protected Inheritance



File: i4.cpp
class Base
{
    public:
     int m_public;
    private:
     int m_private;
    protected:
     int m_protected;
};

class Protect: protected Base
{
    // Protected inheritance means:
    // Public inherited members become protected
    //(so m_public is treated as protected)
    // Protected inherited members become protected
    //(so m_protected is treated as protected)
    // Private inherited members stay inaccessible
    //(so m_private is inaccessible)public:
    public:
    Protect()
    {
        m_public = 1;
        // okay: m_public is now protected in Protect
        //m_private = 2;
        // not okay: derived classes can't access private members
        //in the base class
        m_protected = 3;
        // okay: m_protected is protected in Protect
    }
};
class Derived : public Protect
{
    public:
     Derived()
     {
         m_public = 1 ;
         m_protected = 5 ;
     }
};


int main()
{
    // Outside access uses the access specifiers of the class
    //being accessed.
    // In this case, the access specifiers of base.
    Base base;
    base.m_public = 1;
    // okay: m_public is public in Base
    //base.m_private = 2;
    // not okay: m_private is private in Base
    //base.m_protected = 3;
    // not okay: m_protected is protected in Base
    Protect pri;
    //pri.m_public = 1;
    // not okay: m_public is now protected in Protect
    //pri.m_private = 2;
    // not okay: m_private is inaccessible in Protect
    //pri.m_protected = 3;
    // not okay: m_protected is now protected in Protect
}

Private Inheritance



File: i5.cpp
class Base
{
    public:
    int m_public;
    private:
    int m_private;
    protected:
    int m_protected;
};

class Pri: private Base
    // note: private inheritance
{
        // Private inheritance means:
        // Public inherited members become private
        //(so m_public is treated as private)
        // Protected inherited members become private
        //(so m_protected is treated as private)
        // Private inherited members stay inaccessible
        //(so m_private is inaccessible)
        public:
        Pri()
        {
            m_public = 1;
            // okay: m_public is now private in Pri
            // m_private = 2;
            // not okay: derived classes can't access
            //private members in the base class
            m_protected = 3;
            // okay: m_protected is now private in Pri
        }
};

class Derived : public Pri
{
   public:
   Derived()
    {
        //Compiler error
        //m_protected = 5 ;
    }
};


int main()
{
    // Outside access uses the access specifiers of the class being accessed.
    // In this case, the access specifiers of base.
    Base base;
    base.m_public = 1;
    // okay: m_public is public in Base
    //base.m_private = 2;
    // not okay: m_private is private in Base
    //base.m_protected = 3;
    // not okay: m_protected is protected in Base
    Pri pri;
    //   pri.m_public = 1;
    // not okay: m_public is now private in Pri
    //pri.m_private = 2;
    // not okay: m_private is inaccessible in Pri
    //pri.m_protected = 3;
    // not okay: m_protected is now private in Pri
}


Exercise

Find all the access errors in the below program.

File: ex2.cpp
class Base
{
    public:
    int m_public;
    Base()
    {
        m_private = 3 ;
        }
        private:
        int m_private ;
        protected:
        int m_protected ;
        };
class Derived: public Base
{
  protected:
    int p_var1 ;
  private:
    int p_var2 ;
  public:
    int p_var3 ;
    Derived()
    {
        m_private = 4 ;
        m_protected = 5 ;
        p_var2 = 6 ;
    }
};

class Derived1 : private Derived
{
  public:
    Derived1()
    {
        p_var1 = 4 ;
        p_var2 = 5 ;
        m_public = 6 ;
    }
};

int main()
{
        Base baseObject ;
        Derived derivedObject ;
        Derived1 derived1Object ;
        baseObject.m_public = 1;
        baseObject.m_protected = 2 ;
        derivedObject.m_public = 1 ;
        derived1Object.m_public = 1 ;
        derived1Object.p_var3 = 3 ;
}

Calling the base class constructor

If the base class has a constructor then how can we call it when constructing an object of the derived class ? We can use initialization lists.

File: base1.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
     string firstName  ;
     string lastName ;
     string getName()
     {
         return ( firstName + " " + lastName ) ;
         }
         Person( string firstNameP, string lastNameP )
         {
             firstName = firstNameP ;
             lastName = lastNameP ;
             }
             };

class Employee : public Person
{
  public:
    string jobTitle ;
    Employee( string firstNameP, string lastNameP, string jobTitleP)
                 :Person(firstNameP, lastNameP  )
         {
                 jobTitle = jobTitleP ;
         }
     void print()
     {
             cout << getName() << " " << jobTitle << endl ;
     }
};


int main()
{
  Employee e1( "Alan" , "Turing" , "Programmer" ) ;
  e1.print() ;
  return 0 ;
}


We can only call the immediate base ( parent class constructor ).There is a caveat to this in multiple inheritance.

File: base2.cpp
#include <iostream>
using namespace std ;
//Virtual Destructor
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    //virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
    Person( string firstNameP )
    {
       firstName = firstNameP ;
      cout << "Person Constructor." << endl ;
    }

    //virtual
    ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;

     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee(string firstNameP) : Person( firstNameP )
          {
            cout << "Employee Constructor." << endl ;
          }

         //virtual
         ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager( string firstNameP ): Person( firstNameP ) , Employee( firstNameP )
          {
            cout << "Manager Constructor." << endl ;
          }

         //virtual
         ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{

    return 0 ;
}
$ g++ base2.cpp
base2.cpp: In constructor ‘Manager::Manager(std::string)’:
base2.cpp:64:47: error: type ‘Person’ is not a direct base of ‘Manager’
   64 |                 Manager( string firstNameP ): Person( firstNameP ) , Employee( firstNameP )

If we have same name variables in derived and base classes then we can refer to the base class variable name using the syntax "base::variable" .

File: base3.cpp
#include <iostream>
using namespace std ;


class  Person
{
    public:
    string firstName  ;
    string lastName ;

    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
    Person( string firstNameP )
    {
       firstName = firstNameP ;
       cout << "Person Constructor." << endl ;
    }

    ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;

     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee(string firstNameP) : Person( firstNameP )
          {
          jobTitle = "Employee title." ;
            cout << "Employee Constructor." << endl ;
          }

         ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     string jobTitle ;
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << Employee::jobTitle <<  " Manager" << endl ;

     }
          Manager( string firstNameP ):  Employee( firstNameP )
          {
          jobTitle = "Manager title." ;
            cout << "Manager Constructor." << endl ;
          }

         ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;
    m1 = new Manager( "Chuck" ) ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Boxer" ;
    m1->getName() ;
    //p1 = m1 ;
    //e1->getName() ;
    //Make sure we delete the right type
    //or program will crash
    delete m1 ;

    return 0 ;
}


Exercise

2)Modify the below program so that the constant id in the class Person is set by modifying the constructors of both the Person and Employee class.



File: ex2.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    const int id ;
    string getName()
    {
        return ( firstName + " " + lastName ) ;
    }
    Person( string firstNameP, string lastNameP )
    {
            firstName = firstNameP ;
            lastName = lastNameP ;
    }
};

class Employee : public Person
{
   public:
      string jobTitle ;
      Employee( string firstNameP, string lastNameP, string jobTitleP)
                :Person(firstNameP, lastNameP  )
      {
        jobTitle = jobTitleP ;
      }
    void print()
    {
        cout << getName() << " " << jobTitle << " " << id << endl ;
    }
};


int main()
{
    Employee e1( "Alan" , "Turing" , "Programmer" , 1) ;
    e1.print() ;
    return 0 ;
}

Polymorphism

The word means to take on many forms. If we have a base class and a derived class that have methods of the same name: say a base class "Person" and a derived class called "Employee". We know that an "Employee" is a "Person" so we can upcast a pointer of "Employee" to "Person" but now if we call the common method "getName" what class method should be called; the "Person" or the "Employee".
Polymorphism allows the right ( original ) class method to be called.

File: v1.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    virtual void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
};

class Employee : public Person
{
    public:
     string jobTitle ;
     //virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }
};

int main()
{
    Person* p1 ;
    Employee* e1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Boxer" ;
    p1 = e1 ;
    p1->getName() ;


    delete e1 ;

    return 0 ;
}

The poymorphism does not work with objects but only pointers and references.
1) Virtual functions cannot be static.
2) A virtual function can be a friend function of another class.
3) Virtual functions should be accessed using a pointer or reference
of base class type to achieve runtime polymorphism.
4) The prototype of virtual functions should be the same in the base
as well as the derived class.
5) They are always defined in the base class and overridden in a
derived class. It is not mandatory for the derived class to override
(or re-define the virtual function), in that case, the base class version
of the function is used.
6) A class may have a virtual destructor but it cannot have a
virtual constructor.
Virtual methods are implemented by virtual method tables. Each class will keep a virtual method table keeping pointers to the functions. https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/ If we don't want Polymorphism then we don't use the "virtual" keyword. This saves us resources. Polymorphism begins in the hierarchy when the virtual keyword is declared.
If we have say three classes

A
  method M1
B
 virtual method M1

C
 virtual method M1

Then if we create an object of type C and upcast to A then we will not
have polymorphism. However if we type cast to B then we will have polymorphism.
Also once we write the virtual keyword then we do not need to write the
virtual keyword in the dervied classes methods.


File: v2.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    //virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
};

class Employee : public Person
{
    public:
     string jobTitle ;
      //Polymorphism starts from here
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }
};

class Manager : public Employee
{
    public:
     //ok to leave virtual out
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Boxer" ;
    p1 = e1 ;
    p1->getName() ;
    delete e1 ;

    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Boxer" ;
    e1 = m1 ;
    e1->getName() ;
    //Make sure we delete the right type
    //or program will crash
    delete m1 ;

    return 0 ;
}
If we have the actual object but that object does not have the virtual method defined then we climb up the hierarchy till we find a method definition.

File: v3.cpp
#include <iostream>
using namespace std ;

class  Person
{
    public:
    string firstName  ;
    string lastName ;
    virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
};

class Employee : public Person
{
    public:
     string jobTitle ;
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }
};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
    /* virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     } */
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Boxer" ;
    p1 = m1 ;
    p1->getName() ;
    //Make sure we delete the right type
    //if we don't have virtual destructors
    delete m1 ;

    return 0 ;
}

Virtual Destructor

Anytime we have destructors in our hierarchy and use polymorphism we should make the destructors virtual. That way when we have a pointer to the base class and we do a delete then the derived destructor also gets called.

File: v4.cpp
#include <iostream>
using namespace std ;

//Virtual Destructor
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    //virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
    Person()
    {
      cout << "Person Constructor." << endl ;
    }

    virtual
    ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee()
          {
            cout << "Employee Constructor." << endl ;
          }

         //virtual
         ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

         //virtual
         ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Programmer" ;
    p1 = e1 ;
    p1->getName() ;
    delete p1 ;

    cout << endl << endl << endl ;
    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Programmer" ;
    p1 = m1 ;
    e1->getName() ;
    delete p1 ;

    return 0 ;
}
Output is:
Person Constructor.
Employee Constructor.
Employee Destructor.
Person Destructor.


Person Constructor.
Employee Constructor.
Manager Constructor.
Manager Destructor.
Employee Destructor.
Person Destructor.

If we don't have the destructor as virtual then we get the following results. We may get the right results or not. It is always better to use the virtual keyword for destructors.

File: v5.cpp
#include <iostream>
using namespace std ;
//Virtual Destructor
//We need to make it virtual
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }
    Person()
    {
      cout << "Person Constructor." << endl ;
    }

     ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee()
          {
            cout << "Employee Constructor." << endl ;
          }

          ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

          ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Boxer" ;
    p1 = e1 ;
    p1->getName() ;
    delete e1 ;

    cout << endl << endl ;
    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Boxer" ;
    p1 = m1 ;
    e1->getName() ;
    delete p1 ;

    return 0 ;
}
Output is:
Person Constructor.
Employee Constructor.
Employee Destructor.
Person Destructor.


Person Constructor.
Employee Constructor.
Manager Constructor.
Manager Destructor.
Employee Destructor.
Person Destructor.

We can have a private virtual method in the base calss and it can only be called by the base class method but polymorphism will still occur.

File: v6.cpp
#include <iostream>
using namespace std ;
//Virtual Destructor
//We need to make it virtual
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    Person()
    {
      cout << "Person Constructor." << endl ;
    }

     ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

    void print()
     {
       getName() ;
     }
   private:
       virtual    void getName()
        {
            cout <<  firstName << " " <<  lastName << endl ;
        }


};

class Employee : public Person
{
    public:
     string jobTitle ;
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee()
          {
            cout << "Employee Constructor." << endl ;
            jobTitle = "Employee title." ;
          }

          ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

          ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Programmer" ;
    p1 = e1 ;
    p1->print() ;
    delete e1 ;

/*
    cout << endl << endl ;
    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Manager" ;
    p1 = m1 ;
    e1->getName() ;
    delete m1 ;
*/

    return 0 ;
}
There is also the case of what happens when a virtual method calls a non-virtual method. We have upcasted a derived pointer to a base class pointer and call a virtual method that is implemented in the derived class. Assume we have a non-virtual method implemented in both the classes and now the virtual method in the derived calls this non-virtual method. Which method is going to be called ? In this case the non-virtual method in the derived class will be called.

File: v7.cpp
#include <iostream>
using namespace std ;
//Virtual Destructor
//We need to make it virtual
class  Person
{
    public:
    string firstName  ;
    string lastName ;

    virtual
    void getName()
    {
        cout <<  firstName << " " <<  lastName << endl ;
    }

    void print1()
    {
      cout << "Person::print1()" << endl ;
    }
    Person()
    {
      cout << "Person Constructor." << endl ;
    }

     ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;
         print1() ;
     }
    void print1()
    {
      cout << "Employee::print1()" << endl ;
    }

          Employee()
          {
            cout << "Employee Constructor." << endl ;
          }

          ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

          ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Programmer" ;
    p1 = e1 ;
    p1->print1() ;
    p1->getName() ;
    delete e1 ;



    return 0 ;
}

$ g++ v7.cpp ; ./a.exe
Person Constructor.
Employee Constructor.
Person::print1()
Chuck Wepner Programmer
Employee::print1()
Employee Destructor.
Person Destructor.

Abstract Class

Sometimes we don't want an instance of a class to be created. We can have a pure virtual function in the class without a body in that case.

File: a1.cpp
#include <iostream>
using namespace std ;


//Abstract Class
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    //virtual
    virtual void getName() = 0 ;
    Person()
    {
      cout << "Person Constructor." << endl ;
    }

    virtual ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;

     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     }

          Employee()
          {
            cout << "Employee Constructor." << endl ;
          }

         virtual ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

class Manager : public Employee
{
    public:
     //What if the method is missing
     //Climb up the hierarchy
     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

         virtual ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

   // Compiler error
   // p1 = new Person() ;

    //Allowed
    e1 = new Employee() ;
    delete e1 ;


    return 0 ;
}
In the above code "Person" is an abstract class because it has a pure virtual function named "getName" . The derived class "Employee" implements this class and is not an abstract class.

If the pure virtual function is not implemented in the derived class then the derived class becomes abstract also.

File: a2.cpp

#include <iostream>
using namespace std ;


//Abstract Class
class  Person
{
    public:
    string firstName  ;
    string lastName ;
    //virtual
    virtual void getName() = 0 ;

    Person()
    {
      cout << "Person Constructor." << endl ;
    }

    virtual ~Person()
    {
      cout << "Person Destructor." << endl ;
    }

};

class Employee : public Person
{
    public:
     string jobTitle ;
     //if no implementation for getName
     //then this class is also abstract
     /*
     virtual
     void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle << endl ;

     } */

          Employee()
          {
            cout << "Employee Constructor." << endl ;
          }

         virtual ~Employee()
         {
           cout << "Employee Destructor." << endl ;
         }

};

//This is not an abstract class
class Manager : public Employee
{
    public:

     virtual void getName()
     {
         cout <<  firstName << " " <<  lastName <<
         " " << jobTitle <<  " Manager" << endl ;

     }
          Manager()
          {
            cout << "Manager Constructor." << endl ;
          }

         virtual ~Manager()
         {
           cout << "Manager Destructor." << endl ;
         }
};


int main()
{
    Person* p1 ;
    Employee* e1  ;
    Manager* m1  ;

   // Compiler error
   // p1 = new Person() ;

    //Not Allowed
    //e1 = new Employee() ;
    //delete e1 ;

    //Allowed
    m1 = new Manager() ;
    delete m1 ;



   /*
    e1 = new Employee() ;
    e1->firstName = "Chuck" ;
    e1->lastName = "Wepner" ;
    e1->jobTitle = "Boxer" ;
    p1 = e1 ;
    //p1->getName() ;
    delete e1 ;

    cout << endl << endl ;
    m1 = new Manager() ;
    m1->firstName = "Chuck" ;
    m1->lastName = "Wepner" ;
    m1->jobTitle = "Boxer" ;
    p1 = m1 ;
    //e1->getName() ;
    //Make sure we delete the right type
    //or program will crash
    delete m1 ;
      */
    return 0 ;
}
Using pure and normal virtual functions a userful hierarchy can be implemented where the base class and the derived class work together. In the below program we have a "Vector" object that is able to call a base class method called "printElements" that in turn is able to call the derived class methods even though it has no idea of what the implmentations are at the time the class was written. In fact tomorrow if a new derived class from "Collection" then the method "printElements" will still work.

This area is part of the area that is called design patterns. A book on this topic is listed in the books section of this site.

File: a3.cpp

#include <iostream>
using namespace std ;


//Abstract Class
class  Collection
{
    public:


    virtual int  getSize() = 0 ;
    virtual int getElement( int index ) = 0 ;

    void printElements()
     {
          int size = getSize() ;
          for( int i1=0 ; i1 < size ; i1++ )
            {
              cout << getElement( i1 ) << " " ;
            }
          cout << endl ;
     }


};

class Vector : public Collection
{
    public:
      int getSize()
        {
            return 2 ;
        }


        int getElement( int index )
         {
          if ( index == 0 )
            return 100 ;
          else
            return 200 ;
      }



};


int main()
{

   Vector vectorObj ;
   vectorObj.printElements() ;




    return 0 ;
}

Multiple Inheritance

We can have a class derive from 2 classes.

File: multi1.cpp
#include <iostream>
using namespace std ;

// Base class
class BaseA
{
  public:
    void myFunctionBaseA()
    {
      cout << "Some content in parent class BaseA." << endl ;
    }
};

// Another base class
class BaseB
{
  public:
    void myFunctionBaseB()
    {
      cout << "Some content in parent class BaseB.." << endl ;
    }
};

// Derived class
class MyChildClass: public BaseA, public BaseB
{
};

int main()
{
  MyChildClass myObj;
  myObj.myFunctionBaseA()  ;
  myObj.myFunctionBaseB()  ;
  return 0;
}

Output:
$ rm a.exe ; g++ multi1.cpp ; ./a.exe
Some content in parent class BaseA.
Some content in parent class BaseB..

The diamond problem:
        class A
  class B     class C
         class D

class D inherits 2 copies of class A


File: multi2.cpp
#include<iostream>
using namespace std;

//The diamond problem

class Person {
// Data members of person
public:
    Person(int x) { cout << "Person::Person(int ) called" << endl; }
};

class Faculty : public Person {
// data members of Faculty
public:
    Faculty(int x):Person(x) {
    cout<<"Faculty::Faculty(int ) called"<< endl;
    }
};

class Student : public Person {
// data members of Student
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
    }
};

class TA : public Faculty, public Student {
public:
    TA(int x):Student(x), Faculty(x) {
        cout<<"TA::TA(int ) called"<< endl;
    }
};

int main() {
    TA ta1(30);
}

$ rm a.exe ; g++ multi2.cpp ; ./a.exe
Person::Person(int ) called
Faculty::Faculty(int ) called
Person::Person(int ) called
Student::Student(int ) called
TA::TA(int ) called

We can see that the constructor for Person gets
called twice.
Use the "virtual" on class to prevent 2 copies.

File: multi3.cpp
#include<iostream>
using namespace std;
//Default constructor called for multiple
//inheritance with virtual keyword.


class Person {
public:
    Person(int x) { cout << "Person::Person(int ) called" << endl; }
    Person()     { cout << "Person::Person() called" << endl; }
};

class Faculty : virtual public Person {
public:
    Faculty(int x):Person(x) {
    cout<<"Faculty::Faculty(int ) called"<< endl;
    }
};

class Student : virtual public Person {
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
    }
};

class TA : public Faculty, public Student {
public:
    TA(int x):Student(x), Faculty(x) {
        cout<<"TA::TA(int ) called"<< endl;
    }
};

int main() {
    TA ta1(30);
}

$ rm a.exe ; g++ multi3.cpp ; ./a.exe
Person::Person() called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called

We notice that the default base class constructor
got called instead of the the one with the argument.
What if we didn't have a default base class constructor ?
Then we get a compiler error of the form:

multi3.cpp: In constructor ‘TA::TA(int)’:
multi3.cpp:29:40: error: no matching function for call to ‘Person::Person()’
   29 |         TA(int x):Student(x), Faculty(x) {
      |

Calling the base class constructor when it has an argument.

File: multi4.cpp
#include<iostream>
using namespace std;

//Calling the base class constructor with argument

class Person {
public:
    Person(int x) { cout << "Person::Person(int ) called" << endl; }
    Person()     { cout << "Person::Person() called" << endl; }
};

class Faculty : virtual public Person {
public:
    Faculty(int x):Person(x) {
    cout<<"Faculty::Faculty(int ) called"<< endl;
    }
};

class Student : virtual public Person {
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
    }
};

class TA : public Faculty, public Student {
public:
    TA(int x):Student(x), Faculty(x), Person(x) {
        cout<<"TA::TA(int ) called"<< endl;
    }
};

int main() {
    TA ta1(30);
}

Output:
$ rm a.exe ; g++ multi4.cpp ; ./a.exe
rm: cannot remove 'a.exe': No such file or directory
Person::Person(int ) called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called

We need to make the change in the constructor for the
bottom most class which is "TA" in this case.

TA(int x):Student(x), Faculty(x), Person(x)
The above only works for virtual derived classes. We are not referring to a virtual function here but when the virtual keyword in defining the class.

File: multi5.cpp
#include<iostream>
using namespace std;

//Calling the base class constructor with argument
//will not compile for non virtual cases
class Person {
public:
    Person(int x) { cout << "Person::Person(int ) called" << endl; }
    Person()     { cout << "Person::Person() called" << endl; }
};


class Faculty :  public Person {
public:
    Faculty(int x):Person(x) {
    cout<<"Faculty::Faculty(int ) called"<< endl;
    }
};

class Student :  public Person {
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
    }
};

class TA : public Faculty, public Student {
public:
    TA(int x):Student(x), Faculty(x), Person(x) {
        cout<<"TA::TA(int ) called"<< endl;
    }
};

int main() {
    TA ta1(30);
}


$ rm a.exe ; g++ multi5.cpp ; ./a.exe
multi5.cpp: In constructor ‘TA::TA(int)’:
multi5.cpp:29:43: error: type ‘Person’ is not a direct base of ‘TA’
   29 |         TA(int x):Student(x), Faculty(x), Person(x) {
      |                                           ^~~~~~
bash: ./a.exe: No such file or directory


Exercise:


What do the following programs output ? Explain.

File: ex4.cpp
#include<iostream>
using namespace std;

class A
{
 int x;
 public:
  void setX(int i) {x = i;}
  void print() { cout << x; }
};

class B: virtual public A
{
 public:
   B() { setX(10); }
};

class C: virtual  public A
{
public:
   C() { setX(20); }
};

class D: public B, public C {
};

int main()
{
    D d;
    d.print();
    return 0;
}


File: ex5.cpp
#include<iostream>
using namespace std;

class A
{
 int x;
 public:
  void setX(int i) {x = i;}
  void print() { cout << x; }
};

class B: virtual public A
{
 public:
   B() { setX(10); }
};

class C: virtual  public A
{
public:
   C() { setX(20); }
};

class D: public B, public C {
};

int main()
{
    D d;
    d.print();
    return 0;
}


File: ex6.cpp