Friday, October 27, 2017

Lecture Notes 09

Object Oriented Programming: Lecture Notes 09

Author: A. El-Gadi/Faculty of Computer Engineering/Tripoli University

The hierarchy of types


Things in the world can be of many types. The type to which something belongs, can have many levels of generality. For instance, a dog can be said to be an animal, but it is also a mammal, and is also a canine. Its being a canine does not contradict the fact that it is a mammal, because being a canine entails being a mammal. A canine has every trait a mammal has, in addition to the traits that differentiate canines from other mammals. A cat is, also, a mammal but it is not a canine; because it is differentiated by other traits that make it a feline. However, felines and canines have traits that are common to every mammals. Therefore, canines and felines are said to be similar qua mammals and different qua canines and felines. A chicken is, also, an animal and therefore it has in common with other animals the general traits of animality. However, more specifically a chicken is a bird and differentiating traits of birds are what make it a bird. This hierarchy of types is important and useful for organizing the world around us; because it allows us to extend our knowledge of the general type to whatever sub-type that comes comes under it. For example, once we know that whales are mammals we can extend our knowledge about mammals to whales. We can assert about whales that they lactate, for instance. This hierarchy of types can be captured in object oriented programming using inheritance.

Inheritance


When a class inherits another class all attributes and methods of the inherited class, become attributes and methods of the inheriting class. The inherited class is called super-class, base class or parent class and the inheriting class is called subclass, derived class or child class. Private member variables and functions of the base class are not accessible in the derived class, even though they exist in every in derived class object, because every derived class instance has a base class instance. Public members of the base class, on the other hand, are accessible in the derived class and can be used from derived objects as if they where derived class members. The syntax for the inheritance relationship is as follows:

class Base{private:
        int i;
        int func1(){return 3*i;}
       public:
        int k;
        void set_i(int m){i=m;}
       };

class Derived:public Base{private:
                int n;
              public:
                    int h;
                void set_n(int j){n=j;}
                void square_k(){k=k*k;}/*Allowed because k is a public member variable of Base*/
             };

int main(){Derived d;/*d is created and has Base members as part of it*/
       d.k=9;/*Allowed because k becomes a member by inheritance*/
       d.set_i(18);/*Allowed becasue set_i is a public member of Base and becomes a public member of Derived by inheritance.*/
       d.set_n(10);/*set_n is a public member of Derived*/
       d.square_k();/*Invokation of public member function*/
       return 0;
      }


In the code above, i and privefunc() are not accessible directly in Derived because they are private in Base. With the inheritance relationship a new access modifier called protected is introduced and its role is to make members of base classes accessible to derived classes only. Therefore, if we want to make func1() accessible to derived classes we can make it protected.

class Base{private:
        int i;
       protected:
        int func1(){return 3*i;}/*func1() is now accessible to all derived classes*/
       public:
        int k;
        void set_i(int m){i=m;}
       };

class Derived:public Base{private:
                int n;
              public:
                    int h;
                void set_n(int j){n=j;}
                int ninefold_i(){return 3*func1();}/*func1() is accessible because it is protected*/
             };

int main(){Derived d;
       d.set_i(10);
       cout<<d.ninefold_k();/*Output: 90*/
       return 0;
       }


It is important to understand that objects of derived classes have as part of them objects of base classes.

 --------+--------------------+
  ^      | Base class part    |
  |      |                    |
  |      |                    |
  |      |                    |
  |      |                    |
Derived  |                    |
Object   +--------------------+
  |      | Derived class part |
  |      |                    |
  |      |                    |
  |      |                    |
  |      |                    |
  v      |                    |
 --------+--------------------+


The order of construction of the derived class' object starts with constructing the base class part and then the derived class part. The construction of the base class part uses the default constructor of the base class, even if the derived object is constructed using a parametrized constructor. We will explain in later lectures how this behavior can be overridden.

class Base{private:
        int i;
       public:
        int k;
        void set_i(int h){i=h;}
        Base(){i=10; k=20;}
        Base(int h){i=h;}
       };

class Derived:public Base{public:
                int j;
                Derived(){j=1000;}
                Derived(int g){j=g;}
              };

int main(){Derived d1;/*i=10, k=20, j=1000|Default constructor of base is invoked*/
       Derived d2(555);/*i=10, k=20, j=555|Default constructor of base is invoked*/
       return 0;
      }







No comments:

Post a Comment