Headlines News :
Home » , , » Learn C++ in 12 Days - Day 5

Learn C++ in 12 Days - Day 5

Written By Ente Malayalam on Friday, May 24, 2013 | 5/24/2013

DAY – 5

            Consider the encapsulation done for the dealer. There I have created two objects : john and smith. As I told you yesterday, the moment I create an object, the first step which is going to happen internally is memory allocation. A block of memory corresponding to the attributes will be allocated to you. Now since it is allocated in the stack, we can say that the initial value to which it is initialized is garbage. Since it is initialized to garbage I can say that the object john or smith are in undefined state. So here if ever we forget to invoke the Add_Details() function, we may end up doing garbage manipulation.
            So if ever our object was capable of invoking a function from our class automatically which can help us in initialization, it will be always better. Such a facility is also provided in C++ and it is done using something known as constructors.
            Constructors are special member functions which helps us in initialization of the objects. Why it is called as special member functions is, it gets invoked implicitly at the time of creation of objects. Constructor will always take the name of the class as the function name and this helps the compiler to distinguish between constructors and other functions. Even though it is a function, a constructor doesn’t have any return type not even void. Just like any other function, constructors will also have argument list. Based on arguments, constructors can be classified into two as shown below.


                                                            Constructors

  

        1. Zero argument constructor          
        2. Constructors with arguments

Based on the type of the arguments, constructors with arguments can be further classified as follows.

                                                Constructor with arguments


 


            1. Parameterized constructors                             
            2. Copy constructors



Lets try to modify our dealer program with constructors. We will just see default / zero argument constructor and parameterized constructor now. We will talk about copy constructor once we are done with our dynamic memory allocation.







//Header file for Dealer in CDS

#include <iostream>
using namespace std;

class Dealer    {
        public:
                Dealer()        {
                        cout << "Enter your name" << endl;
                        cin >> Name;
                        No_Cars_Sold = 0;
                        Price = 200000;
                        Comm_Rate = 0.16;
                        Comm_Per_Car = 0.0;
                        Total_Comm = 0.0;
                }
                Dealer(char *n) {
                        strcpy(Name, n);
                        No_Cars_Sold = 0;
                        Price = 200000;
                        Comm_Rate = 0.16;
                        Comm_Per_Car = 0.0;
                        Total_Comm = 0.0;
                }
                void Sell_Car();
                void Change_Comm_Rate(float);
                float Report_Comm();
        private:
                char Name[20];
                int No_Cars_Sold;
                int Price;
                float Comm_Rate;
                float Comm_Per_Car;
                float Total_Comm;
};

//dealer_library.cpp

#include "dealer_header.h"

void Dealer :: Sell_Car()       {
        No_Cars_Sold += 1;
        Comm_Per_Car = Price * Comm_Rate;
        Total_Comm += Comm_Per_Car;
}

void Dealer :: Change_Comm_Rate(float Comm_Rate)        {
        this -> Comm_Rate = Comm_Rate;
}

float Dealer :: Report_Comm()   {
        return Total_Comm;
}

//dealer_application.cpp

#include "dealer_header.h"

int main()      {
        Dealer John;

        John.Sell_Car();
        cout << John.Report_Comm() << endl;

        Dealer Smith("Stephen Smith");

        Smith.Change_Comm_Rate(0.20);
        Smith.Sell_Car();
        cout << Smith.Report_Comm() << endl;

        return 0;
}

            Lets start from the first step. When an object is created, first a block of memory is allocated for the object equivalent to the size of the class. Construction of the object is not over by this step. After memory allocation it invokes the constructor for initialization of the memory. Which constructor is invoked is purely based on whether you are passing arguments along with the object or not. 
            Here the object John will be invoking the default argument constructor and object Smith will be invoking the parameterized constructor. If you notice here you can see that I have defined the constructors in the public section of the class. So naturally question arises : can I write the constructor in the private section of the class.
            Putting a constructor in the private section of the class restricts the creation of objects of that class. Consider the case when object anu is created. As we discussed before, immediately after memory allocation, it tries to invoke the constructor for initialization. To reach the private constructor, it need to seek the help of a member function defined in the public section of the class. But with a partially constructed object, will we be ever able to invoke a member function. No. So there is no way we can reach the private constructor of the class which restricts the creation of object.



I am just modifying the application layer of the above program.
#include "dealer_header.h"

int main()      {
        Dealer John = Dealer("Abraham John");

        Dealer Smith;
        Smith = Dealer("Stephen Smith");

        return 0;
}

Will this work?? If you notice the syntax, it seems to be like the constructor function is getting invoked on the RHS and vinu on LHS is waiting for a return type from this function. Infact some books refers it to as explicit call of constructors. But not exactly. Syntax for real explicit call is
Dealer John;
John.Dealer(“Abraham John”);

This is not allowed at all in our language. The reason / explanation is : constructors are meant for construction cum initialization of the object. If the object John is already created why do we have to invoke the constructor again.
The thing which happens in the first case is : in the first statement compiler forces object John to invoke the constructor and in the second statement a temporary object is created which invokes the constructor and the initialized temporary object will get copied to Smith. So that is not exactly explicit call of constructor. Explicit call always refers to invoking something with a dot operator.

So summarizing:
Constructors are special member functions of the class. As a function, it do have a function name and function argument but no return type. Constructor will take the class name. They should be written in the public section of the class for successful object creation and it helps us in initialization of the object. 

From the above discussion, you might have understood that constructors are playing very vital role in object creation. Let me ask you one question. Till yesterday’s class when we were writing programs, did we ever bothered about the constructors. No right. Even then it was working perfectly. Or in other words, object creation was taking place perfectly right. So what was happening there? The object was getting created there because when you don’t write any constructors in your class, by default you compiler provides you a default argument / zero argument constructor. The only problem with that constructor is it initializes the members only to garbage. So it is always preferable to write our own constructors in our programs which initializes the members to user specified values.


All these time we were talking about functions which helps us in construction of the objects. So by this time you might have guessed that there will be some one who is going to help us in destruction also right. It is none other than another special member function named as destructor.

Destructor:
            Destructors are special member functions of the class which helps us in cleaning up activities when object comes out of the scope. Just like constructor, destructors also share the same name with constructor. To distinguish between constructors and destructors, destructor function have to be preceded by a ~ symbol. If you are not writing a destructor, compiler by default will give you a destructor  
            Modifying the above program with a destructor
//Header file for Dealer in CDS

#include <iostream>
using namespace std;

class Dealer    {
        public:
                Dealer()        {}
                Dealer(char *n) {
                        strcpy(Name, n);
                        No_Cars_Sold = 0;
                        Price = 200000;
                        Comm_Rate = 0.16;
                        Comm_Per_Car = 0.0;
                        Total_Comm = 0.0;
                }
                ~Dealer()       {}
                const Dealer& operator= (const Dealer &);
                void Sell_Car();
                void Change_Comm_Rate(float);
                float Report_Comm();
        private:
                char Name[20];
                int No_Cars_Sold;
                int Price;
                float Comm_Rate;
                float Comm_Per_Car;
                float Total_Comm;
};




//dealer_library.cpp

#include "dealer_header.h"

void Dealer :: Sell_Car()       {
        No_Cars_Sold += 1;
        Comm_Per_Car = Price * Comm_Rate;
        Total_Comm += Comm_Per_Car;
}

void Dealer :: Change_Comm_Rate(float Comm_Rate)        {
        this -> Comm_Rate = Comm_Rate;
}

float Dealer :: Report_Comm()   {
        return Total_Comm;
}

//dealer_application.cpp

#include "dealer_header.h"

int main()      {
        Dealer John;

        John.Sell_Car();
        cout << John.Report_Comm() << endl;

        Dealer Smith("Stephen Smith");

        Smith.Change_Comm_Rate(0.20);
        Smith.Sell_Car();
        cout << Smith.Report_Comm() << endl;

        return 0;
}


If you notice you can see that I have written a destructor without anything in the body. Ie) it is similar to the destructor provided by the compiler. This is because, in this program, there is only stack memory allocation. All the stack memory is automatically reclaimed when the object comes out of the scope. Only when dynamic memory allocation occurs, users have to explicitly de-allocate the memory. Only in such situations we have to write our own destructors. Till that point it is perfectly ok to utilize the destructor provided by the compiler. So we will be talking more about these destructors once we are done with DMA.
            Now in the above program, can you tell me the order of construction and order of destruction? The order of construction will be first John and then Smith. But the order of destruction will be first Smith and then John. Y ? It is purely due to the stack arrangement. Stack is last in first out. So the object which went inside last is Smith. So it is popped out first. Or concluding, the order of construction and destruction will always be in the reverse.

Before moving further lets learn few things about dynamic memory allocation in C++.

Dynamic memory allocation:
            Since c++ have backward compatibility with C language, it completely supports the dynamic memory allocation techniques supported by C. ie) it supports malloc,realloc, calloc and free. In addition to this, for better memory management, c++ designers have provided us with two new operator named as new and delete.
            New and delete have two different versions, one for normal variable and one for arrays. The syntax of new and delete for normal variables is
            New  data-type;
            delete data-type;

The syntax of new and delete for arrays is
            new data-type[size]
            delete []  data-type

Let’s take an example. Consider a normal integer pointer :
int *ptr. See the difference in memory allocation using malloc, free and new, delete.
 

Malloc() & free()                                                                     new & delete

For variables                                                                            for variables
Ptr = (int*) malloc(sizeof(int));                                               ptr = new int;
Free(ptr);                                                                                 delete ptr;

For arrays                                                                                for arrays
Ptr = (int*) malloc(20 * sizeof(int));                                       ptr = new int[20];
Free(ptr);                                                                                 delete [] ptr;



The major differences between these two memory allocation techniques are

  1. malloc and free are functions where as new and delete are operators. Even though they are operators, don’t ever think that it is going to avoid the function overheads. This is because new and delete internally calls two functions, operator new and operator delete respectively.
  2. In new and delete, explicit type casting and size of operator is not needed. Every thing is taken care of internally.
  3. Malloc() when fails returns NULL where as new when it fails it returns a runtime error. Since we haven’t learnt how to handle the runtime errors, for the time being we will just modify the syntax of the new to throw NULL when it fails. The syntax you have to use is
new (nothrow) data-type
            &
new (nothrow) data_type
           
The nothrow version forces new to return NULL when it fails. So this will be the version of new which we are going to use for the next few classes.

  1. Another major difference between malloc, free and new, delete is while dealing with the memory allocation of objects, new always calls the constructor and delete always calls the destructor where as malloc n free never calls the constructors and destructors.
  2. to enhance the above feature, there is one more feature added along with new. Ie) memory initialization at the time of allocation. For eg.            
Ptr = new int(10);
is perfectly legal in new. Here four bytes of memory for integer is allocated and it will be initialized with 10. This feature is very very essential while allocating memory for objects. As I told you, while allocating memory for object, it calls the constructors internally right. So this memory initializer list can be used to pass the arguments to the parameterized constructor of the class.

Lets try to apply the above mentioned concepts to our classes and objects and lets c how it works. We will take the same dealer example here also.

//Header file for Dealer in CDS

#include <iostream>
using namespace std;

class Dealer    {
        public:
                Dealer()        {
                        Name = new (nothrow) char[20];
                        if(Name == NULL)        {
                                cout << "Mem allocation failed" << endl;
                                exit(1);
                        }
                        cout << "Enter your name" << endl;
                        cin >> Name;
                        No_Cars_Sold = 0;
                        Price = 200000;
                        Comm_Rate = 0.16;
                        Comm_Per_Car = 0.0;
                        Total_Comm = 0.0;
                }
                Dealer(char *n) {
                        Name = new (nothrow) char[strlen(n) + 1];
                        if(Name == NULL)        {
                                cout << "Mem allocation failed" << endl;
                                exit(1);
                        }
                        strcpy(Name, n);
                        No_Cars_Sold = 0;
                        Price = 200000;
                        Comm_Rate = 0.16;
                        Comm_Per_Car = 0.0;
                        Total_Comm = 0.0;
                }
                void Sell_Car();
                void Change_Comm_Rate(float);
                float Report_Comm();
                ~Dealer()       {
                        delete [] Name;
                }
        private:
                char *Name;
                int No_Cars_Sold;
                int Price;
                float Comm_Rate;
                float Comm_Per_Car;
                float Total_Comm;
};

//dealer_library.cpp
#include "dealer_header.h"

void Dealer :: Sell_Car()       {
        No_Cars_Sold += 1;
        Comm_Per_Car = Price * Comm_Rate;
        Total_Comm += Comm_Per_Car;
}

void Dealer :: Change_Comm_Rate(float Comm_Rate)        {
        this -> Comm_Rate = Comm_Rate;
}

float Dealer :: Report_Comm()   {
        return Total_Comm;
}


//dealer _application.cpp
#include "dealer_header.h"

int main()      {
        Dealer John;
        Dealer Smith("Stephen Smith");
        Dealer *Jack = new Dealer;
        Dealer *Jill = new Dealer("Jill");
        delete Jack;
        delete Jill;

        return 0;
}


For the above program, the memory picture will be as shown below.



 Now when these objects comes out of the scope, delete automatically calls the destructor. So first, the fourty bytes allocated which is pointed by Jack will be deallocated and then the next 40 bytes pointed by Jill will be deallocated. Rest is purely last in first out basis
            So by this time you will be clear with the advantages of new and delete which made us shift from malloc, free to new and delete. Here onwards we will be sticking to the memory allocation techniques specific to c++ in our programs.





 
Share this article :

0 comments:

Post a Comment

 
Support : Creating Website | Johny Template | Maskolis | Johny Portal | Johny Magazine | Johny News | Johny Demosite
Copyright © 2011. Education World - All Rights Reserved
Template Modify by Creating Website Inspired Wordpress Hack
Proudly powered by Blogger