C++ - inheritance

Created:2018-01-25  Last modified:2018-01-25


  1. Introduction

    Inheritance: is-a (vs. has-a) architecture, child contains class. Natural and good for code reusing.

    Subclasses automatically inherit all Parent classes's members except *structors (Even though the subclasses cannot directly access parent private members, but they are also inherited. )

    Different from Java, C++ inheritance allows mutli-inheritance

    It also has public/protect/private modifier before parent name.

  2. Examples

    1. Constructor inheritance

      Either child's compiler-provided or user-provided default/non-default constructor would FIRST call Parent default constructor, then do it self. (same as Java)

      Using c++ std11, child constructor use initialization list to choose a specific parent constructor.

      Exact one of parent constructor must be called first in the every child constructor.

       
              #include <iostream>
              using namespace std;
              class Parent{
              public:
                  Parent();
              };
              Parent::Parent(){
                  cout << "Parent constructor" << endl;
              }
              class Child: public Parent{
                  
              };
              
              int main(){
                  Parent p; // Parent constructor
                  Child c; // Parent constructor
                  return 0;
              }
                  
      

      Source code

      
      #include <iostream>
          using namespace std;
          class Parent{
          public:
              Parent();
              Parent(int x, int y);
          };
          Parent::Parent(){
              cout << "Parent constructor" << endl;
          }
          Parent::Parent(int x, int y){
              cout << "Parent (int, int) constructor" << endl;
          }
          class Child: public Parent{
          private:
              int x;
              int y;
          public:
              Child();
              Child(int x, int y);
              Child(int x, int y, int z);
          };
          Child::Child(){
              // Parent(); syntax is ok, but this is actually just to create a Parent object without assignment.
              cout << "Child constructor" << endl;
          }
          Child::Child(int x, int y):x(x), y(y){
              this->x = x;
              this->y = y;
              cout  << "Child (int, int) constructor" << endl;
          }
          Child::Child(int x, int y, int z):Parent(x,y){ //using initialization list to choose a non-default parent constructor.
              cout << "Child (int, int, int) constructor" << endl;
          }
          int main(){
              Parent p; // Parent constructor
              Child c; //  Parent constructor /n Child constructor
              Child c1(1,1); //Parent constructor /n Child (int, int) constructor
              Child c2(1,1,1); // Parent (int, int) constructor /n Child (int, int, int) constructor
              return 0;
          }
      
    2. The requirement for a parent default constructor

      In some cases, the parent class may not have the default constructor either provided by the compiler or defined by the user. However, because the subclass's constructors would implicitly invoke the parent's default constructor, it would cause compilation error. To avoid this issue, 1) always having a default constructor; or 2) explicitly invoking parent's own constructors.

      #include <iostream>
      using namespace std;
      
      class F{
      public:
          F(int x){cout << "F(int x) constructor" << endl; }
      };
      class E: public F{
          
      };
      
      int main(){
          E e; //no matching function for call to ‘F::F()’ class E: public F{
      
          return 0;
      }
      
      #include <iostream>
      using namespace std;
      
      class F{
      public:
          F(int x){cout << "F(int x) constructor" << endl; }
      };
      class E: public F{
      public:
          E():F(1){} // explicitly call F(int )
      };
      
      int main(){
          E e; 
      
          return 0;
      }
      
    3. Initialization list order

      The order of element in the initialization does not matter. e.g. :x(x), y(y), Parent(x,y) is OK. But the real initialization order is Parent, arguments in declaration order.

    4. Override parent private functions

      The parent private function is invisble to child class, so the child

    5. Override & Call super class method

      Subclasses automatically inherit all Parent classes's members except constructor (Even though the subclasses cannot directly access parent private members, but they are also inherited).

      However, if the subclass define a method to override a parent method (the two methods have same signature: name + same order arguments), but the child still wants to call its parent version, then it has to use Parent:: syntax

      C++ does not have super like keywork (e.g. super in Java), perhaps because C++ support multiple inheritance.[1]

      Source code

          #include <iostream>
              using namespace std;
              class Parent{
              public:
                  Parent();
                  void display();
              };
              Parent::Parent(){
                  cout << "Parent constructor" << endl;
              }
              void Parent::display(){
                  cout << "Parent display" << endl;
              }
              
              //========
              class Child: public Parent{
              public:
                  Child();
                  void display(); // if child wants to override a function, it has to explicitly declare the function.
              };
              Child::Child(){
                  cout << "Child Constructor" << endl;
              }
              void Child::display(){
                  Parent::display(); // invoke parent's display
                  // display();// this causes infinite recursion
                  cout << "Child display "  <<  endl;
              }
              int main(){
                  Child c; // Parent constructor /n Child constructor
                  c.display(); // Parent display /n Child display
                  return 0;
              }
      
    6. Override member variables

      Override member variable can modify variable's access modifier, and variable's type. Also it will create a new storage area for this new variable and still has space for parent.

      If the parent's functions access the parent's variable, the child inherited functions still go to access the inherited parent's variable instead of child newly defined varaibles.

    7. Modes of inheritance: public, protected and private

    8. Override changes the modifers

      Override can also override the modifer. The child class can make public parent functions to be private or protected. In this case, outside of the child class cannot invoke this function anymore. In order to call the child class function, a virtual function can be used..

      #include <iostream>
      using namespace std;
      class F{
      protected:
          int x = 0; 
          void print(){cout << "P protected print!" << endl; }
      public:
          virtual void draw(){cout << "P public draw!" << endl; }
          void showX(){ cout << x << endl;} // a new x is defined in child, but parent still use its self x
      };
      class E: public F{
      public:
          int x; // child override parent's variable
          void print(){cout << "C public print!"  << endl; }
      protected:
          void draw(){cout << "C protected draw!" << endl; }
      };
      int main(){
          E e;
         // e.draw();// ‘void E::draw()’ is protected
          e.print();
          e.x = 10;
          e.showX();
          F * f = new E();
          f->draw(); // invoke child protected...
          return 0;
      }
      
    9. Mutli-inheritance

      
      
  3. References

    1. Problem solving with C++ 9th edition, P846
    2. Inheritance in C++ - GeeksforGeeks
    3. C++ does not have super keyword.