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;
      }







Saturday, October 21, 2017

Lecture Notes 08

Object Oriented Programming: Lecture Notes 08

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

Below is the code for assignment 01 along with some commentary in the form of code comments. Make sure to read it through.


const double PI=3.14159;

/*The cup material and the liquid are included here as separate classes to as a design measure to make room for any future expansion of the concepts of liquid and solid material. Another design direction is to include their densities in the cup class.*/
class SolidMaterial{public: double density;
            SolidMaterial(){density=0;};
            SolidMaterial(double dens){density=dens;}};

class Liquid{public: double density;
             Liquid(){density=0;};
             Liquid(double dens){density=dens;}};

/*A cylinder object to use for cylinder proprieties; because our cup can be thought of as two coaxial cylinders.*/
class Cylinder{public: double radius; double height;
            double volume(){return PI*radius*radius*height;}
            Cylinder(){radius=0; height=0;};
            Cylinder(double r, double h){radius=r; height=h;}
        };

class Cup{private:
      /*The inner cylinder, which constitutes inner cavity of the cup*/
      Cylinder innerCylinder;
      /*The outer cylinder, determined by the inner cylinder and the cup thickness.*/
      Cylinder outerCylinder(){return Cylinder(innerCylinder.radius+thickness,innerCylinder.height+thickness);}
      double thickness;

      SolidMaterial cupMaterial;
      Liquid lq;
      double lqamount;

      public:
      /*Setting the cup attributes. The diameter is used because real life cylinders are normally given by their diameter. Using the radius instead is also fine.*/
      void setCup(double diameter, double innerht, double t, double cupmatdens){
        innerCylinder.radius=diameter/2; innerCylinder.height=innerht;
        thickness=t; cupMaterial.density=cupmatdens; lqamount=0;}
     
      /*Set liquid density. We can also use a liquid object.*/
      void setLiquid(double density){lq.density=density;}
   
      /*Fill the cup with a certain amount. If the amount exceeds the remaining capacity of the cup fill to brim.*/
      void fill(double amount){
        if(amount<=innerCylinder.volume()-lqamount){
            lqamount+=amount;
        }
        else
        {fill();}
        }

      void fill(){lqamount=innerCylinder.volume();}
      /*Empty a certain amount from the cup. If the amount to be poured exceeds the amount in the cup, empty the cup.*/
      void empty(double amount){
        if(amount<=lqamount){
            lqamount-=amount;
        }
        else
        {empty();}
        }

      void empty(){lqamount=0;}
      /*Take note of how we got the outer cylinder volume. Try to explain it to yourself.*/
      double tare(){return (outerCylinder().volume()-innerCylinder.volume())*cupMaterial.density;}

      double lqweight(){return lqamount*lq.density;}
   
      double weight(){return tare()+lqweight();}

      Cup(){setCup(0,0,0,0); lqamount=0;}
      /*Construct an empty cup*/
      Cup(double diameter, double innerht, double t, double cupmatdens, double lqdens){
        setCup(diameter,innerht,t,cupmatdens); lqamount=0; lq.density=lqdens;}
      /*Construct a cup that has a certain amount of liquid*/
      Cup(double diameter, double innerht, double t, double cupmatdens, double lqdens, double amnt){
        setCup(diameter,innerht,t,cupmatdens); fill(amnt); lq.density=lqdens;}

    };

Thursday, October 19, 2017

Lecture Notes 07

Object Oriented Programming: Lecture Notes 07

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

 

Arrays contd.


Arrays of objects can be allocated statically and used in the way familiar to C programmers. The default constructor is automatically used when creating the objects that constitute the elements of the array.

class AA{public: int d,e;
     int mul(){return d*e;}};

int main(){AA aaar[10];
    aaar[7].d=10;
    aaar[7].e=11;
    cout<<aaar[7].mul();//Output: 110
    }


Arrays can be allocated dynamically, as well. This is accomplished using the new keyword. Dynamically allocated arrays must, eventually, be explicitly deleted. The example below illustrate the syntax for accomplishing dynamic allocation. Only the default constructor can be used for the dynamic allocation of arrays.

class AA{public: int d,e;
     int mul(){return d*e;}};

int main(){AA *paa;
   
    paa=new AA[10];/*Dynamic allocation of an array of type AA of size 10*/
    paa[7].d=10;
    paa[7].e=11;
    cout<<paa[7].mul();//Output: 110
    delete [] paa;
    return 0;
    }


Since in the case of arrays, only default constructors are allowed, populating arrays is done in a later step. The code below uses a loop to populate a dynamically allocated array, and then displays the result on the console using another loop:

class AA{public: int d,e;
     int mul(){return d*e;}};

int main(){AA *paa;
   
    paa=new AA[10];
   
    int i;
    for(i=0;i<10;i++){cin>>paa[i].d; cin>>paa[i].e;}

    for(i=0;i<10;i++){cout<<paa[i].mul();}

    delete [] paa;
   
    return 0;
    }


Copy constructors


Copy constructors are used to create objects that are exact copies of other objects. A full treatment of the syntax involved in defining copy constructors can be somewhat complicated at this stage, but the basic idea is simple. A Copy constructor takes one object of same type of the class as a parameter, and copies each member variable of the passed object to the corresponding member variable in the object being created. As such, the prototype of the copy constructor for some class AAA should look like this AAA(AAA). In practice, however, the mentioned copy constructor's prototype looks like this AAA(const AAA&). The const keyword here tells the compiler that the object passed is constant and therefore should be immutable. The importance of the const keyword in this context becomes clear when we consider the role of the ampersand (&). The ampersand here is different from the ampersand used to get a pointer of an object or a variable, and is confusingly called reference in the context of C++. It is an addition to C++ that forces a function -in this case the copy constructor- to use the original object or variable in its original memory space rather than copy it to the function's memory space. This feature is especially important in OOP; because most of the time we find ourselves dealing with large objects, which are expensive to copy from one memory space to another. But allowing a function to work on the original object exposes it to modification. Therefore, the keyword const is prepended to it to prevent such a any modification from taking place. The copy constructor is supplied by the compiler and need not be overridden unless there is a plausible reason to do so. One such typical reason is having a deep class, whose pointer member(s) referent(s) need to be copied explicitly in the overridden copy constructors to avoid having a shared referent. The following code correctly uses the default copy constructor for a shallow class:

class AA{public: int d,e;};

int main(){AA aa1;
    aa1.d=33; aa1.e=99;
   
    AA aa2(aa1);

    cout<<aa2.d<<' '<<aa2.e;//Output: 33 99

    return 0;
    }



The diagram below illustrates a deep object aa1 of type AA after assigning values to members and member(s) of pb referent object. Note that the code below is defective since it does not override the copy constructor:

class BB{public:int x;}

class AA{public: int d,e;
     BB *pb;
     AA(){pb=new BB();}
     ~AA(){delete pb;}
    };

int main(){AA aa1;
    aa1.d=10; aa1.e=30;
    aa1.pd->x=70;
    return 0;
    }

aa1                    Obj1 BB@address 16000
+------------+    +--->+--------+
|            |    |    |        |
| d: 10      |    |    | x: 70  |
|            |    |    +--------+
| e: 30      |    |
|            |    |
|pb:16000+--------+
|            |
+------------+


Here is the situation we will end up with when using the default copy constructor for a deep class. It is evident that this situation leads to all kinds of problems because of the shared referent. Consider what would happen when aa1.pb->x is changed. Since we have the same referent, aa2.pb->x will be changed as well. Even worse, in the case of dynamically allocated objects, when the first object is deleted the other object will have a pointer pointing to a deallocated memory space.

class BB{public:int x;}

class AA{public: int d,e;
     BB *pb;
     AA(){pb=new BB();}
     ~AA(){delete pb;}
    };

int main(){AA aa1;
    aa1.d=10; aa1.e=30;
    aa1.pd->x=70;

    AA aa2(aa1);
    return 0;
    }

aa1                    Obj1 BB@address 16000
+------------+    +-->>+--------+
|            |    | |  |        |
| d: 10      |    | |  | x: 70  |
|            |    | |  +--------+
| e: 30      |    | |
|            |    | |
|pb:16000+--------+ |
|            |      |
+------------+      |
                    |
                    |
aa2                 |
+------------+      |
|            |      |
| d: 10      |      |
|            |      |
| e: 30      |      |
|            |      |
|pb:16000+----------+
|            |
+------------+


To solve the problem above, we need to override the copy constructor to perform a deep copy when we have deep classes. See the code and the diagram below:

class BB{public:int x;}

class AA{public: int d,e;
     BB *pb;
     AA(){pb=new BB();}
     AA(const AA& aa){d=aa.d; e=aa.e; pb=new BB(*aa.pb);}
     ~AA(){delete pb;}
    };

int main(){AA aa1;
    aa1.d=10; aa1.e=30;
    aa1.pd->x=70;

    AA aa2(aa1);
    return 0;
    }

aa1                    Obj1 BB@address 16000
+------------+    +--->+--------+
|            |    |    |        |
| d: 10      |    |    | x: 70  |
|            |    |    +--------+
| e: 30      |    |
|            |    |
|pd:16000+--------+
|            |
+------------+


aa2                    Obj2 BB@address 24000
+------------+    +--->+--------+
|            |    |    |        |
| d: 10      |    |    | x: 70  |
|            |    |    +--------+
| e: 30      |    |
|            |    |
|pd:24000+--------+
|            |
+------------+


Design consideration when a value is determined by other member variables


When deciding which member variables to include in a class, it is important to keep in mind the following guiding principle:
If some information about the object can be determined by other member variables this information should not be included as a member variable but rather it should be calculated from other member variables. For example, assume that we want to design a rectangle class, and among the information that we wish to be able to retrieve from our class is the area and the perimeter of the rectangle. In such a class, if we include the area and the perimeter as member variables our design would be flawed because the area and the perimeter can be calculated by knowledge of the side lengths of the rectangle. Here is the flawed class:

class Rectangle{public:
        double height;
        double width;
        double area;
        double perimeter;
        };


The reason that this design is flawed is because it is prone to inconsistent values of the height, length, area, and perimeter. We can have an object that has 5 for height, 10 for width, 70 for area and 40 for perimeter. Making area and perimeter functions that perform a calculation of the area and perimeter and return their values circumvents the aforementioned problem. The correct design should be as follows:

class Rectangle{public:
        double height;
        double width;
        double area(){return height*width;}
        double perimeter(){return 2*(height+width);}
        };


That is why when we designed a Triangle class and chose to determine a triangle by the lengths of the three sides, we did not include member variables for area and perimeter. Nor should we include member variables for the triangle's angles, since any angle can be calculated by knowledge of the side lengths of the triangle's sides which are included as member variables in the class.

Monday, October 16, 2017

Lecture Notes 06

Object Oriented Programming: Lecture Notes 06

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

Destructors


We have seen that constructors are used to create objects. When execution exits the scope of the object, the object is destroyed. The destruction part is done by the destructor, which can be overridden to control how an object is destroyed.

class A{public: int k;};

int main(){A a1;
   
    return 0;/*Destructor is called here as scope exits when main returns*/
    }


As with constructors, every class is supplied with a default destructor. If not overridden the default constructor will simply release the memory occupied by the object. It should be noted that, in contrast to constructors, destructors cannot be overloaded, which means that there is always one destructor that takes no arguments. The code below illustrate the syntax of overriding the default destructor:

class A{public: int k;
    ~A(){cout<<"Object is destroyed\n";}
    };

int main(){A a1;
   
    return 0;/*Output: Object is destroyed*/
    }


It should be clear that destructors are the most unlikely place to communicate with the user through the console, and is done here for illustration purpose only. A good and typical use of destructors will be mentioned below when we consider deep objects. To understand what a deep object is, we need to make understand how pointers work in C++.

Pointers and the new and delete operators


As every C programmer knows, pointers are memory addresses that refer to the location of a variable. In addition to C-like pointers, pointers to objects also exist. When declaring a pointer to a basic type (float, int, char ..etc.) the referent of the pointer is created along with the pointer. However, when a pointer to an object is declared the referent of the pointer needs to be created independently. The keyword new is reserved for this purpose in C++. It creates an object and returns a pointer to the object. To access member variables and member functions of the object the arrow operator -> is used in the case of pointers. Below is an example of the use of the new operator.

class A{public: double x,y;
        double mul(){return x*y;}
    };

int main(){A *pa; /*Declares a pointer to an object of type A. The object does not exist yet.*/
      
       pa=new A(); /*An object of type a is created and its address is returned.*/
       pa->x=3.2;
       pa->y=0.2;
       cout<<pa->mul();//Output: 0.64
       /*There is something missing here*/
       return 0;
    }


This code, however, will cause compilation error because we are attempting to access a member of a non-existent object:

class A{public: double x,y;
        double mul(){return x*y;}
    };

int main(){A *pa; /*Declares a pointer to an object of type A. The object does not exist yet.*/

       pa->x=18; /*Compilation error. The object is not existent yet.*/
       return 0;
    }


Objects created using the new operator are said to be dynamically allocated because they are allocated at the run-time. For this reason, they should be deallocated when no longer needed. This is accomplished using the delete operator and is normally placed at the end of the scope where the object was created. Failing to delete dynamically allocated objects results in memory leaks, with all their concomitant problems. It is important to realize that C++ does not implement automatic garbage collection as in other languages (e.g. Java); because automatic garbage collection leads to a less efficient code. C++ also allows for more control at the side of the programmer. The code above is, therefore, produces a memory leak because the object was not deleted. Here is the code after fixing it:

class A{public: double x,y;
        A(double u, double w){x=u;y=w;}
        double mul(){return x*y;}
    };

int main(){A *pa; /*Declares a pointer to an object of type A. The object does not exist yet.*/
      
       pa=new A(); /*An object of type a is created and its address is returned.*/
       pa->x=3.2;
       pa->y=0.2;
       cout<<pa->mul();//Output: 0.64
       delete pa;/*Object deleted*/
       return 0;
    }


What the delete operator actually does, is invoke the class destructor. Take for example the following code:

class A{public: double x;
        ~A(){cout<<"Bye Bye";}
    };

int main(){A *pa; /*Declares a pointer to an object of type A. The object does not exist yet.*/
      
       pa=new A(); /*An object of type a is created and its address is returned.*/

       delete pa;/*Output: Bye Bye*/
       return 0;
    }


This brings us to one of the typical usages of destructors; namely deep classes and their objects.

Deep classes/objects


A deep class is a class that has one or more pointers member variables. The presence of such member variables mandates extra care when designing the class. First, the objects to which the pointers should point need to be created dynamically, usually, somewhere in the class. Those dynamically created objects, need to be destroyed when the object whose member pointers point to them is destroyed. Otherwise, they will stay hanging in memory and cause a memory leak. Below is an example of a deep class, together with the proper design of the destructor.

class AA{public: int d,e;};

class BB{public: int f,g;
    AA *a;
    BB(){a=new AA();}
    ~BB(){delete a;}
};


Indeed, a class can be of any depth. If the dynamic creation and deletion of objects is taken care of, the design remains the same.


class AA{public: int d,e;};

class BB{public: int f,g;
    AA *a;
    BB(){a=new AA();}
    ~BB(){delete a;}
};

class CC{public: int h,i;
    BB *b;
    CC(){b=new BB();}
    ~CC(){delete b;}
    };


There are more considerations, to pay attention to, when designing deep classes, but we will leave them for the time being.

It is important, to mention in that member arrays do not lead to deep objects. Therefore, the class below is a shallow class.

class AA{public: int d,e;

          int ar[4];};/*This array is inside the bounds of the class*/

And class DD is shallow as well.

class AA{public: int d,e;};

class DD{public:
        AA aaar[4];
    };






Friday, October 13, 2017

Assignment 01

Assignment 01


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

A simplified cup can be modeled as a cylinder of uniform thickness and a base that has the same thickness. Both the cylinder and the base are made of the same material, which is given by its density. The cup can be filled with a certain amount of liquid -again given by its density-, and a certain amount of the liquid can be poured out of the cup. There should be a function to get the tare of the cup, a function to get the weight of the liquid in the cup and a function to get the overall weight of the cup and the liquid. There, should also be a function to fill the cup with a certain amount of liquid and a function to pour a certain amount of liquid. If the amount of liquid is not specified when filling the cup, the cup should be filled to the brim, and if the amount of liquid to be poured is not specified the cup should be emptied. When created a cup should be empty, but it can also be created with a certain amount of liquid in it. Write a class that captures the concept of a glass as described above making sure to disallow any illogical and inconsistent values for the different variables and parameters in your class.

Assignment due on Tuesday, October 17, 2017

Lecture Notes 05

Object Oriented Programming: Lecture Notes 05

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

If not overridden, the default constructor would simply allocate memory when the class is instantiated i.e. an object is created. A class can have multiple constructors. To understand, how is this possible we need to understand the idea of function overloading.

 

Function overloading:


Function overloading is the ability to have more than one version of the function that differ only in their passing parameters, but have identical names and return types. Take the following example:

void func1(int x){cout<<"This is the INT version";}
void func1(double x){cout<<"This is DOUBLE double version";}

int main(){int y1; double y2;

func1(y1);//Output: This is the INT version
func1(y2);//Output: This is the DOUBLE version
return 0;
}


In the code above the appropriate function is called based on the passing parameter's type. The compiler will choose the version that matches or closely matches the type of the passing parameter. Therefore, if we pass a float in the code above, the function that takes double as passing parameter will be called.

void func1(int x){cout<<"This is the INT version";}
void func1(double x){cout<<"This is DOUBLE double version";}

int main(){float y;

func1(y);//Output: This is the DOUBLE version
return 0;
}


It is also possible to have overloaded functions for types of the same 'family' such as floats and doubles. However, this is not advisable because it does not meet the expectations of the programming community, which normally expects types of the same family to be cast to one another, rather than being treated differently. Therefore, the example below compiles and runs but is ill-designed:

void func1(float x){cout<<"This is the FLOAT version";}
void func1(double x){cout<<"This is DOUBLE version";}

int main(){float y1; double y2;

func1(y1);//Output: This is the FLOAT version
func1(y2);//Output: This is the DOUBLE version
return 0;
}


Class member functions can also be overloaded. Take the following TimePeriod class. Assume that minutes are as accurate a time as we desire to have. We also want to have a function to add minutes and a function to display the period of time.

class TimePeriod{private:
        int minutes;
        public:
        TimePeriod(){minutes=0;}
        void display(){int h,m; h=minutes/60; m=minutes-h*60;
                cout<<h<<':'<<m;}
        void addMinutes(int m){minutes+=m;}
        int get(){return minutes;}
        };



But it is also natural to add time in hours as well. We can include another member function to add time in hours, and our class would end up looking like this:

class TimePeriod{private:
        int minutes;
        public:
        TimePeriod(){minutes=0;}
        void display(){int h,m; h=minutes/60; m=minutes-h*60;
                cout<<h<<':'<<m;}
        void addMinutes(int m){minutes+=m;}
        void addHours(int h){minutes+=h;}
        int get(){return minutes;}
        };


However, a better approach that keeps the user of our class from deciding which function to choose when adding time is to overload functions to do the different tasks addMinutes and addHours do. This requires that we have minutes and hours as differentiated types.

class Minutes{public: int min;};
class Hours{public: int hours;};

class TimePeriod{private:
        int minutes;
        public:
        TimePeriod(){minutes=0;}
        void display(){int h,m; h=minutes/60; m=minutes-h*60;
                cout<<h<<':'<<m;}

        void addTime(Minutes m){minutes=minutes+m.min;}
        void addTime(Hours h){minutes=minutes+h.hours*60;}
        int get(){return minutes;}
        };

int main(){Minutes m1; Hours h1; TimePeriod tp1;
        m1.min=30; h1.hours=3;
        tp1.addTime(m1);//This will call the first overloaded addTime
        tp1.addTime(h1);//This will call the second overloaded addTime
        tp1.display();//Output: 3:30
        return 0;
        }

   

We can even include a function that accepts both hours and minutes and another one that accepts another period of time.

class Minutes{public: int min;};
class Hours{public: int hours;};

class TimePeriod{private:
        int minutes;
        public:
        TimePeriod(){minutes=0;}
        void display(){int h,m; h=minutes/60; m=minutes-h*60;
                cout<<h<<':'<<m;}

        void addTime(Minutes m){minutes=minutes+m.min;}
        void addTime(Hours h){minutes=minutes+h.hours*60;}
        void addTime(Hours h, Minutes m){addTime(h); addTime(m);}
        void addTime(TimePeriod tp){minutes=minutes+tp.get();}
        int get(){return minutes;}
        };

int main(){Minutes m1; Hours h1; TimePeriod tp1, tp2;
        m1.min=30; h1.hours=3;
        tp1.addTime(m1);//This will call the first overloaded addTime
        tp1.addTime(h1);//This will call the second overloaded addTime
        tp1.display();//Output: 3:30
       
        tp2.addTime(m1);//Adds 30 minutes
        tp2.addTime(tp1);//Adds 210 minutes
        tp2.addTime(h1,m1);//Adds 210 minutes
        cout<<'\n';
        tp2.display();//Output: 7:30

        return 0;
        }

 

Constructor overloading:


To return to our initial concern -that of having multiple constructors- we will add that constructors too can be overloaded. This allows users of the class to initialize objects with the desired values. A constructor that takes parameters is called parametric constructor as opposed to the default constructor that takes no parameters. The following is the class TimePeriod after adding some parametric constructors. In the function main you can find the syntax for the usage of parametric constructors.


class Minutes{public: int min;};
class Hours{public: int hours;};

class TimePeriod{private:
        int minutes;
        public:
        TimePeriod(){minutes=0;}
        TimePeriod(Minutes m){minutes=m.min;}
        TimePeriod(Hours h){minutes=h.hours*60;}
        TimePeriod(Hours h, Minutes m){minutes=h.hours*60+m.min;}
       
        void display(){int h,m; h=minutes/60; m=minutes-h*60;
                cout<<h<<':'<<m;}

        void addTime(Minutes m){minutes=minutes+m.min;}
        void addTime(Hours h){minutes=minutes+h.hours*60;}
        void addTime(Hours h, Minutes m){addTime(h); addTime(m);}
        void addTime(TimePeriod tp){minutes=minutes+tp.get();}
        int get(){return minutes;}
        };

int main(){Minutes m1; Hours h1;
       m1.min=40; h1.hours=2;

       TimePeriod tp1(m1);//Initialize with Minutes object
       TimePeriod tp2(h1);//Initialize with Hours object
       TimePeriod tp3(h1,m1);//Initialize with Hours and Minutes

       tp1.display();//Output: 0:40
       tp2.display();//Output: 2:0
       tp3.display();//Output: 2:40
       return 0;
    }

   





Monday, October 9, 2017

Lecture Notes 04

Object Oriented Programming: Lecture Notes 04

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

Objects of the following triangle class can easily be assigned inconsistent values. The triangle inequality rule, for example, is not guaranteed to hold; because side1, side2 and side3 are public (see the code below).

class Triangle{public:
        double side1;
        double side2;
        double side3;
        double perimeter(){return side1+side2+side3;}
        };


int main(){Triangle t1;
    t1.side1=10; t1.side1=7; t1.side1=1.5;/*triangle inequality rule violated*/
    return 0;
    }



In what follows, we will advance slowly towards a correct design solution to this problem by exploring intermediate steps and finding out how object oriented principles can solve the emerging issues.

One way to solve this problem is to inform our class users to adhere to the rules that govern a triangle when assigning values to its sides of a triangle through the use of comments. Our class would look like the following:


class Triangle{public:
        /*When assigning values to side1, side2, and side3, make sure not to violate the triangle inequality; that is, never let any side be greater than the sum of the two other sides*/   
        double side1;
        double side2;
        double side3;
        double perimeter(){return side1+side2+side3;}
        };



This is of course is a very small improvement because it relies solely on how disciplined the user of the class is. The correct approach, which employs the principles of object oriented programming, is to disallow any direct assignment of the sides of the triangle by hiding them i.e. by making them private, as shown in the code below:


class Triangle{private:
        double side1;
        double side2;
        double side3;
        public:       
        double perimeter(){return side1+side2+side3;}
        };


The class above is, of course, useless; as there is no way to access its member variables outside the scope of the class. Therefore, we need to supply public member functions to access our private members setter/getter pairs. It should also be obvious that, setter member functions -aka mutator methods- are the appropriate place to validate data before assigning it to the class members. Accordingly, our class should end up looking like the following:

class Triangle{private:
        double side1;
        double side2;
        double side3;

        public:   
        void setSide1(double x){
            if(
side2+side3>x&&side2+x>side3&&side3+x>side2){side1=x;}
            }

        double getSide1(){return side1;}

        void setSide2(double x){
            if(
side1+side3>x&&side1+x>side3&&side3+x>side1){side2=x;}
            }

        double getSide2(){return side2;}

        void setSide3(double x){
            if(
side2+side1>x&&side2+x>side1&&side1+x>side2){side3=x;}
            }

        double getSide3(){return side3;}

        double perimeter(){return side1+side2+side3;}
        };


The class above checks if the triangle inequality is met before setting the value of a supplied side length. The class is still useless, nonetheless, because when a triangle object is created, the initial values of side1, side2,and side3 will hold whatever value there is in the memory allocated for the object. It is not guaranteed that those values would not, by coincidence, be in disagreement with the conditions: side2+side3>x; side1+side3>x; side2+side1>x above. Let us assume, for example, that side1, side2,and side3 hold the values 98765445.322222, 734853.987, 9383929.33002 at the moment of the object's creation. If we wish to set the sides to the values 10.5 7.3 and 14.11 our attempt would fail for every side. To solve this problem, it seems reasonable to find a way to perform validation only when the other two sides have been set. This means that we should keep track of which sides have been set and which ones have not been set. The obvious programming technique to employ in such a situation is include a flag corresponding to each side. The flag value is set to true when the corresponding side is set. The initial value of each flag should be false, but for the time being we will have to defer the treatment of this issue to the next step. Our flags belong naturally to the private part of the class for three reasons: 1) They should be safeguarded from any tampering. 2) They are not an intrinsic part of the concept of a triangle. Their reason of being in the class is that of practicality. 3) They constitute an added complexity that is best kept hidden from the user.

class Triangle{private:
        double side1;
        bool flag1;
        double side2;
        bool flag2;
        double side3;
        bool flag3;

        public:   
void setSide1(double x){
            if(!(flag2&&flag3)){side1=x; flag1=true;}
            else{
            if(side2+side3>x&&side2+x>side3&&side3+x>side2){side1=x; flag1=true;}}
            }

        double getSide1(){return side1;}

        void setSide2(double x){
            if(!(flag1&&flag3)){side2=x; flag2=true;}
            else{
            if(side1+side3>x&&side1+x>side3&&side3+x>side1){side2=x; flag2=true;}}
            }

        double getSide2(){return side2;}

        void setSide3(double x){
            if(!(flag2&&flag1)){side3=x; flag3=true;}
            else{
            if(side2+side1>x&&side2+x>side1&&side1+x>side2){side3=x; flag3=true;}}
            }

        double getSide3(){return side3;}

        double perimeter(){return side1+side2+side3;}
        };



This class should work fine, if only we had a way to initialize the flags to false. Fortunately, OOP allows programmers to control the creation of an object through constructors. Constructors can be thought of as member functions that are executed at the moment of an object's instantiation. They are distinguished by having a name identical to the class' name and no return values. Here is our Triangle class after adding a constructor that initializes all flags to false.

class Triangle{private:
        double side1;
        bool flag1;
        double side2;
        bool flag2;
        double side3;
        bool flag3;

        public:   
        void setSide1(double x){
            if(!(flag2&&flag3)){side1=x; flag1=true;}
            else{
            if(side2+side3>x){side1=x; flag1=true;}}
            }

        double getSide1(){return side1;}

        void setSide2(double x){
            if(!(flag1&&flag3)){side2=x; flag2=true;}
            else{
            if(side1+side3>x){side2=x; flag2=true;}}
            }

        double getSide2(){return side2;}

        void setSide3(double x){
            if(!(flag2&&flag1)){side3=x; flag3=true;}
            else{
            if(side2+side1>x){side3=x; flag3=true;}}
            }


        double getSide3(){return side3;}

        double perimeter(){return side1+side2+side3;}

        Triangle(){flag1=false; flag2=false; flag3=false;}
        };

int main(){Triangle t; /*Triangle() is executed and thus all flags are set to false*/
       t.setSide1(10); t.setSide2(20); t.setSide3(150);
       cout<<t.getSide1()<<' '<<t.getSide2()<<' '<<t.getSide3()<<endl;
       return 0;
      }


We will have more to say about constructors later.

Friday, October 6, 2017

Lecture Notes 03

Object Oriented Programming: Lecture Notes 03
Author: A. El-Gadi/Faculty of Computer Engineering/Tripoli University


Member functions:


In addition to member variables, classes can have member functions; also known as methods. Member functions are chosen to be expressive of how a class behaves. They encapsulate the class behavior in the class in the same way member variables encapsulate class attributes. The following Rectangle class illustrates the use of member functions and their invocation.

class Rectangle{public:
        double width;
        double height;
        double area(){return width*height;}
        double perimeter(){return 2*(width+height);}
        };

int main{Rectangle r1,r2;
    r1.height=10; r1.width=30.5;
    r2.height=100; r2.width=70;

    double temp;
    temp=r1.area();
    temp=r2.perimeter();
    return 0;
    }



The member functions above can be rewritten outside the body of the class using the scope operator :: , whose function is to tell the compiler to which class a function belongs. Declarations inside the class body, however, must be supplied. The scope operator becomes even more important with large functions, whose implementation if included in the class body can render the class definition unreadable. The following example illustrates the use of scope operator with two classes that have functions with similar names.

class Rectangle{public:
        double width;
        double height;
        double area();
        double perimeter();
        };

double Rectangle::area(){return width*height;}
double Rectangle::perimeter(){return 2*(width+height);}

class Circle{public:
        double radius;
        double area();
        };


double Circle::area(){return 3.14159*radius*radius;}

int main{Rectangle r1; r1.height=10; r1.width=30.5;
    Circle c1; c1.radius=5;

    double temp;
    temp=r1.area();//Returns the value 10*30.5
    temp=c1.area();//Returns the value 3.14159*5*5
    return 0;
    }


Objects as member variables:

Member variables are not limited C++ basic types. User defined types can also be member variables. Suppose that we want to design a class for a rectangular door which has a height a width and thickness, and whose area and perimeter we will calculate using member functions. Our door class should look something like this:

class Door{public:
        double width;
        double height;
        double thickness;
        double area(){return width*height;}
        double perimeter(){return 2*(width+height);}
        };


You should be able to notice that Door has every attribute and member function that the class Rectangle has. This is a good situation to include Rectangle object as a member of Door and reuse the functionality of the class Rectangle. Our new class should look like the following. Notice how the height and width are accessed through the Rectangle object:


class BetterDoor{public:
        Rectangle r;
        double thickness;
        };

int main{BetterDoor bd1;
    bd1.r.width=100; bd1.r.height=200; bd1.thickness=5;
    return 0;
    }


Data and complexity hiding:

One of most important tenets of the object oriented philosophy is that of data hiding and complexity hiding. Data hiding is the principle that states that any data that the user of the class does not need to see and manipulate should be hidden from him/her. This serves two goals. First the hidden data becomes inaccessible and thus impossible to tamper with, and any data that strictly belongs to the inner workings of the class is hidden to facilitate an effortless understanding of the class.

In the class BetterDoor above, some complexity has arisen from the inclusion of a Rectangle object. Accessing width and height now has become less natural than before; because normally the height and width of a door are never thought of as the height and width of the rectangle the comprises the door. Nevertheless, when using the class BetterDoor we could only access those two dimensions in the mentioned unnatural way. To solve this problem, we can hide the Rectangle object using the private keyword. The private keyword makes what follows it accessible only to the member functions of the class, and any attempt to access them outside the class' scope would result in a compilation-time error. After making the rectangle object private we can add member functions to access it, and change it in the natural way we desire. The resultant redesign looks like this:

class EvenBetterDoor{public:
        Rectangle r;
        public:
        double thickness;
        void setH(double x){r.height=x;}
        double getH(){return r.height;}
        double setW(double x){r.width=x;}
        double getW(){return r.width;}
        };

int main{EvenBetterDoor bd1;
    bd1.setW(100); bd1.setH(200); bd1.thickness=5;
    temp=bd1.getW();
    temp=bd1.getH();
    return 0;
    }


Hiding data is also important when directly changing that it can result in a corrupted object. Take for example the case of a triangle class defined by the lengths of its three sides. It would seem straightforward that we can assign the lengths to the sides directly by allowing the sides of the triangle to be public as follows:

class Triangle{public:
        double side1;
        double side2;
        double side3;
        double perimeter(){return side1+side2+side3;}
        }


But once we realize that the lengths of the sides of the triangle are governed by the triangle inequality rule, which states that for any triangle the sum of two sides is greater than or equal to the remaining side. Therefore, a better design of a triangle class should take into account that this rule is never violated. The first step in ensuring such a behavior is to hide the sides of the triangle.

Monday, October 2, 2017

Lecture Notes 02

Object Oriented Programming: Lecture Notes 02
Author: A. El-Gadi/Faculty of Computer Engineering/Tripoli University

C-style structs come close to achieving one of the central pillars of object oriented programming called encapsulation. Encapsulation in its fullest sense is the principle of encapsulating all attributes and behavior of some type as an integral part of the type. To achieve encapsulation in the fullest sense of the term, we need more than C-style structs for reasons that will become clear later. In the terminology of OOP this concept is called class. Classes are used to define and describe kinds of things (tables, bottles, cars, human beings, mathematical equations, numbers and so on). Each class is a general statement about the kind it describes. In C++, the class syntax in its simplest can look like the following:

class Rectangle{public:
        double height;
        double width;
        };


The class above is a class that defines a rectangle. The keyword public is used to make the attributes or member variable that come after it visible to the outside. Its importance will become clear later in the course.

The following example illustrates how to use our simple class:

class Rectangle{public:
        double height;
        double width;
        };

#include<iostream>

int main(){Rectangle r1; double temp;
temp=r1.height+r1.width;
}


Notice how we could access the member variable of the class using the dot operator. The syntax, as you might have noticed, is akin to the struct syntax. Also note that the new type Rectangle is not preceded by the keyword class when defining objects of its type.