Tuesday, November 21, 2017

Lecture Notes 10

Object Oriented Programming: Lecture Notes 10

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

We have seen how, that by default, the default constructor of the base class is used to construct the base part of the derived class this behavior can be overridden to force the base part of the derived class to be constructed using one of the overloaded versions of the base class constructors. This allows us to control how the initialization is to be carried out and in certain situations, such as when there the base class has private members it can be the only way to assign those values. To override the default behavior of the construction, initialization lists are used.

Initialization lists


An initialization list is a syntax that got introduced in C++ and its task is to initialize members of the class in a way different from simple assignment during construction time, we will talk about the difference later, but for the time being let us see the syntax so that we can anchor our discussion in a concrete piece of code. The following class uses familiar assignment to set the values of the data.

class AA{public:
     int a;
     double b;
     A(){a=0; b=2.34;}
     A(int aa,double bb){a=aa; b=bb;}
    };


The following class is identical in every respect except that it use initialization lists instead of simple assignment.

class AA{public:
     int a;
     double b;
     A():a(0), b(2.34){};
     A(int aa,double bb):a(aa),b(bb){};
    };


In the code above the member variable to left will take whatever value there is between the parentheses. A different way of achieving the above is the following.

class AA{public:
     int a;
     double b;
     A():A(0,2.34){};
     A(int aa,double bb):a(aa),b(bb){};
    };


We can list a constructor in the initialization list to make it construct the object using some specific values we wish the member variables to hold. This feature is what allows us to override the construction behavior of the base part of a derived class in the case of inheritance, because we can list one of the base class constructors in the initialization list of a derived class constructor.

class Base{public:
        int a;
        double b;
        Base(){};
        Base(int aa, double bb){a=aa; b=bb;}
      };

class Derived:public Base{public:
                int x;
                double y;
                Derived():Base(10,0.1){};
                Derived(int xx, double yy):Base(2*xx,2*yy),x(xx){y=b*yy;}
            };


The difference in behavior that we mentioned earlier lies in that assignment created the variable and then changes its value using the assignment operator =. In the case of initialization lists the values are set at the instant of creation which means that there is no assignment taking place. This has huge consequences, because, in the case of const member variables it is not allowed to change there values after creation. Therefore, the only opportunity to give them a meaningful value is at the moment of creation, and this can only be accomplished using initialization lists. The existence of private member variables of the base class is also another situation where an initialization list is the only possible way to give them meaningful values.

Polymorphism


Inheritance in OOP is the way to capture the type/subtype relationship. We have seen how inheritance makes public and protected member variables and member functions of a base class, available in its derived classes. This is sufficient enough in many situations except when the behavior of some member function of the base class is different when inherited in the derived class. Take for example the general behavior of walking. A human walks in a way that is different from an ostrich or a crocodile. Moreover, different subtypes of humans walk in different manners. For instance, a man walks differently from a woman. This fact can be captured in the OOP framework by overriding the base class function, as in the code below.

class Human{public:
        double age;
        double height;
        void walk(){cout<<"Walk like a human.";}
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };


class Woman:public Human{public:
        int xx;//Some woman attribute.
        void walk(){cout<<"Walk like a woman.";}
       };

int main(){Human h1; Man m1; Woman w1;
       h1.walk();//Output: Walk like a human.
       m1.walk();//Output: Walk like a man.
       w1.walk();//Output: Walk like a woman.
       return 0;}


When we contemplate the reality of things, we realize that the attributes of a subtype include and often add to the attributes of its type. This means that an object of some type cannot fully represent an object of one of the subtypes of the type to which it belongs. This situation is called slicing in OOP, and corresponds to assigning objects of a subclass to objects of its super-class. Object slicing is indeed undesirable. Below is an example of object slicing.

class Human{public:
        double age;
        double height;
        void walk(){cout<<"Walk like a human.";}
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

class Woman:public Human{public:
        int xx;//Some woman attribute.
        void walk(){cout<<"Walk like a woman.";}
       };

int main(){Human h1; Man m1;
        h1=m1;//Object sliced. xy is lost.
        return 0;
    }


However, we can refer to a man or a woman instance as human without contradiction. In other words we can point to an instance of a subclass using a pointer of type super-class. This is logical because, the fact that all men are human does not entail them losing their manhood and the fact that women are human does not entail them losing their womanhood. This is the rationale behind allowing the following syntax in OOP.

class Human{public:
        double age;
        double height;
        void walk(){cout<<"Walk like a human.";}
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

class Woman:public Human{public:
        int xx;//Some woman attribute.
        void walk(){cout<<"Walk like a woman.";}
       };

int main(){Human *ph1; Man m1;
        ph1=&m1;//No object copying, so no slicing
        return 0;
      }


In the code above, we can point to a man using a pointer of type human. However, the attributes specific to the class Man are inaccessible through this pointer, and this is all too natural; because referring to a man as a human should preclude us from addressing the respects in which that human is a man. But there is a small problem; when we make a man walk using the walk function, a man walks like a human rather than like a man. This is similar to changing specific behavior of an individual when referred to using a more general type to which it belongs. In other words, when we pick out a man on the street by pointing a finger at him and say "this human", he does not, magically, change his walking behavior into a more general human gate. This is unrealistic and therefore undesirable; because we know that the human pointer is in actuality pointing to a man, who walks in a manner specific to men.

class Human{public:
        double age;
        double height;
        void walk(){cout<<"Walk like a human.";}
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

class Woman:public Human{public:
        int xx;//Some woman attribute.
        void walk(){cout<<"Walk like a woman.";}
       };

int main(){Human *ph1; Human *ph2; Man m1; Woman w1;
        ph1=&m1;
        ph2=&w1;
        ph1->walk();//Output: Walk like a human.
        ph2->walk();//Output: Walk like a human.
/*Despite the existence of member functions for specific Man and Woman walking behavior, both pointers use the general walking behavior of class Human.*/
        return 0;
      }



The more logical behavior is for a man is to walk like a man and a woman to walk like a woman, even when pointed to by a pointer of a more general type. This effect can be achieved by virtualizing the functions whose behavior should change according to the type/subtype of the object a pointer is pointing to. The syntactical solution is to prepend the function by the keyword virtual.

class Human{public:
        double age;
        double height;
        virtual void walk(){cout<<"Walk like a human.";}
       };


class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

class Woman:public Human{public:
        int xx;//Some woman attribute.
        void walk(){cout<<"Walk like a woman.";}
       };

int main(){Human *ph1; Human *ph2; Man m1; Woman w1;
        ph1=&m1;
        ph2=&w1;
        ph1->walk();//Output: Walk like a man.
        ph2->walk();//Output: Walk like a woman.
/*Both pointers use the specific Man and Woman walking behavior.*/
        return 0;
      }


Now that we know how to make a class behave in the desired way, we will have to go back, and see if there is any change that needs to be done to our classes when we have inherited them, and we will find that destructors need to be declared virtual if they are to behave in the required way. If the destructor is not declared virtual, then when destroying an object through it a super-class pointer only the part of the object that comes from the super class will be destroyed. The following code illustrates the problem:

class Human{public:
        double age;
        double height;
        virtual void walk(){cout<<"Walk like a human.";}
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

int main(){Human *ph1;
       ph1=new Man;
       delete ph1; //Only the part of the object that comes from Human will be destroyed, leaving the rest of the object dangling in memory.
       return 0;
      }


The solution is to make the destructor virtual, so that the type, to which the pointer points, is checked and its version of the destructor is called.

class Human{public:
        double age;
        double height;
        virtual void walk(){cout<<"Walk like a human.";}
        virtual ~Human(){};
       };

class Man:public Human{public:
        int xy;//Some man attribute.
        void walk(){cout<<"Walk like a man.";}
       };

int main(){Human *ph1;
       ph1=new Man;
       delete ph1; //Since the destructor is virtual the type pointed to will be checked and its destructor will be used. Here the destructor of Man will be called, which in turn will call the destructor of human. leaving nothing of the object in memory.
       return 0;
      }

Thursday, November 2, 2017

Questions

Questions.
Use this post to ask questions regarding the part we have covered so far.

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.

Saturday, September 30, 2017

Lecture Notes 01

Object Oriented Programming: Lecture notes 1

Author: A. El-Gadi/Tripoli University

1) The evolution of computer programming

The history of computer programming can be summarized as the quest to make programming computers more natural to human beings. In that sense, the story of the evolution of programming is the story making programming more compatible with the natural way people think about the world around them.
At the dawn of computing, we were content with being able to enter programs into computers in binary format. Where each machine instruction is represented by a unique binary code. Writing a program in machine code was indeed a tedious and error-prone task which constituted a barrier in the way of building larger and more complex program. Listing 1 shows an example of machine code in binary along with the corresponding assembly code and the c language code from which the machine code was produced.
The next step in the evolution of programming was the invention of assembly language, which is basically a set of mnemonics that correspond to machine instructions. Those mnemonics were chosen to be descriptive of what an instruction did. Simple as it is, the principle upon which assembly was based, greatly simplified the task of programmers making them more productive and more capable of tackling more complex tasks. However, assembly suffered from a serious shortcoming, namely that its syntax is an almost direct mapping of the machine architecture. This meant that programming in assembly involved following closely the way the machine operated; see listing 1 to appreciate what adding 4 numbers and storing them in a variable looks like. This also meant that assembly programmers had to think about the specifics of the machine they were programming in order to accomplish their tasks.
High level programming languages sought to overcome this limitation by separating the logic part from the machine part. This is called abstraction -i.e. Abstracting the language from the details of the machine. High level language design philosophy revolves around making the programmer thing about the problem at hand -its logical, relational, structural components- and forgetting about the hardware at hand. The details of converting (compilation) a high level code to the proper machine code is left to the compiler which ”knows” the architecture of the machine in which it is installed.

#include<stdio.h>
void main(){int h=15,i=31,j=63,k=127,m=255,n=511;
h=i+j+k+m;}

01) 1100 0111 0100 0101 1110 1000 0000 1111 0000 0000 0000 0000 0000 0000     mov    [bp-0x18],15
02) 1100 0111 0100 0101 1110 1100 0001 1111 0000 0000 0000 0000 0000 0000     mov    [bp-0x14],31
03) 1100 0111 0100 0101 1111 0000 0011 1111 0000 0000 0000 0000 0000 0000     mov    [bp-0x10],63
04) 1100 0111 0100 0101 1111 0100 0111 1111 0000 0000 0000 0000 0000 0000     mov    [bp-0xc],127
05) 1100 0111 0100 0101 1111 1000 1111 1111 0000 0000 0000 0000 0000 0000     mov    [bp-0x8],255
06) 1100 0111 0100 0101 1111 1100 1111 1111 0000 0001 0000 0000 0000 0000     mov    [bp-0x4],511
07) 1000 1011 0100 0101 1111 0000                                             mov    ax,[bp-0x10]
08) 1000 1011 0101 0101 1110 1100                                             mov    dx,[bp-0x14]
09) 0000 0001 1100 0010                                                       add    dx,ax
10) 1000 1011 0100 0101 1111 0100                                             mov    ax,[bp-0xc]
11) 0000 0001 1100 0010                                                       add    dx,ax
12) 1000 1011 0100 0101 1111 1000                                             mov    ax,[bp-0x8]
13) 0000 0001 1101 0000                                                       add    ax,dx
14) 1000 1001 0100 0101 1110 1000                                             mov    [bp-0x18],ax 

Listing 1: A C language code along with the corresponding machine and assembly code.
This big step is what enabled programmers to write statements like h=i+j+k+m without ever thinking of how this line is going to actually be executed in the machine.
Carrying on with motif of making programming languages even more natural, object oriented programming OOP exploited the fact that the most natural way a human being thinks about the world is thinking about it as being made up of objects with properties and behavior and the relations that govern how these objects interact. By enabling programmers to model the way of everyday thinking, the object oriented methodology avoids many of the problems inherent in purely procedural programming languages.

2) C struct’s as a stepping stone to OOP

In the world of C programming the closest one can get to object oriented programming is through using structs. Let us say that one wishes to write a program to compute the area of a rectangle. Let us compute the the area of three of them in our code. A purely procedural approach without using structs would look something like this: 
#include<stdio.h>

float area(float side1, float side2){return side1*side2;}

void main(){float r1s1=10,r1s2=20,r2s1=30,r2s2=100,r3s1=200,r3s2=300;
float temp;
temp=area(r1s1,r1s2);
temp=area(r2s1,r2s2);
temp=area(r3s1,r3s2);

In the above code we have to take special care not to mix up subscripts and every time we invoke the area function we would have to pass the two sides as parameters.
The following example illustrates the problem even more clearly. Let us write a code to compute the circumference of a heptagon. 

#include<stdio.h>

float circumference(float side1, float side2, float side3, float side4, float side5, float side6, float side7){return side1+side2+side3+side4+side5+side6+side7;}

void main(){
float p1s1=10,p1s2=20,p1s3=30,p1s4=15,p1s5=25,p1s6=16,p1s7=13;
float p2s1=5,p2s2=3,p2s3=5,p2s4=6,p2s5=7,p2s6=2,p2s7=3;
float p3s1=100,p3s2=130,p3s3=140,p3s4=70,p3s5=80,p3s6=50,p3s7=50;

float temp;
temp=circumference(p1s1,p1s2,p1s3,p1s4,p1s5,p1s6,p1s7);
temp=circumference(p2s1,p2s2,p2s3,p2s4,p2s5,p2s6,p2s7);
temp=circumference(p2s1,p2s2,p2s3,p2s4,p2s5,p2s6,p2s7);
}
 

 
A solution that uses structs avoids the problem of having to pay special attention to each passing parameter encapsulating all the information about our object, the heptagon, in one struct.
#include<stdio.h>

struct Heptagon{float side1;float side2;float side3;float side4;float side5;float side6;float side7;};

float circumference(struct Heptagon p){return p.side1+p.side2+p.side3+p.side4+p.side5+p.side6+p.side7;}
/*struct here is passed by value to avoid introducing several new ideas in the same time*/

void main(){struct Heptagon p1,p2,p3;

p1.side1=10,p1.side2=20,p1.side3=30,p1.side4=15,p1.side5=25,p1.side6=16,p1.side7=13;
p2.side1=5,p2.side2=3,p2.side3=5,p2.side4=6,p2.side5=7,p2.side6=2,p2.side7=3;
p3.side1=100,p3.side2=130,p3.side3=140,p3.side4=70,p3.side5=80,p3.side6=50,p3.side7=50;

float temp;
temp=circumference(p1);
temp=circumference(p2);
temp=circumference(p3);

Another advantage of struct’s is that of abstracting from the details of that which it encapsulates. What this means is that after preparing the object we can forget about its details. Let’s say we have a pyramid with rectangular base. We want write a code to compute its volume as well as the area of its base. We will first implement a solution without structs. A pyramid of a rectangular base can be determined by the side lengths of the base rectangle and its height from the base. Let us assume that we want to be able to calculate both its volume and the base area. A solution that does not employ structs looks like this:
#include<stdio.h>

float volume(float height, float baseside1, float baseside2){return height*baseside1*baseside2/3;}
float basearea(float baseside1, float baseside2){return baseside1*baseside2;}

void main(){float h=7,bs1=4,bs2=5;
float temp;
temp=volume(h,bs1,bs2);
temp=basearea(bs1,bs2);

The shortcoming of this approach is that there is no check on whether the parameters passed really represent the correct entities. For example, basearea can be mistakenly called like this basearea(bs1,h) leading to disastrous consequences and a debug nightmare.
A better approach is to employ structs let each function pick out the right set of struct variables from the struct. This way, we are protected from mistakes of the kind mentioned above. 

#include<stdio.h>

struct Rectpyramid{float height; float baseside1; float baseside2;};

float volume(struct Rectpyramid pyr){return pyr.hight*pyr.baseside1*pyr.baseside2/3;}
float basearea(struct Rectpyramid pyr){return pyr.baseside1*pyr.baseside2;}

void main(){struct Rectpyramid pyr1;
pyr1.height=7; pyr1.baseside1=4; pyr1.baseside2=5;
float temp;
temp=volume(pyr1);
temp=basearea(pyr1);
}