Lecture No.08                       

01.1.     Member Functions

          Member functions are the functions that operate on the data encapsulated in the class
          Public member functions are the interface to the class

01.2.     Defining Member Functions
We can define member functions in two ways,
  1. We can define member functions of the class inside the class definition when we define any class in our program.
OR
  1. We declare member function inside the class definition and declare them outside the class.

In this case class definition is added in ClassName.h file and class implementation code is added in ClassName.cpp file.

Function definition inside the class:

General Syntax:
class ClassName {
     …
     public:
     ReturnType FunctionName() {
           …
     }
};


Example:
Define a class of student that has a roll number. This class should have a function that can be used to set the roll number

class Student{
     int rollNo;
public:
     void setRollNo(int aRollNo){
           rollNo = aRollNo;
     }
};



Function definition outside class


General Syntax:

class ClassName {
     …
     public:
     ReturnType FunctionName();

};
ReturnType ClassName::FunctionName()
{
     …

}

Example

class Student{
     …
     int rollNo;
public:
     void setRollNo(int aRollNo);
};
void Student::setRollNo(int aRollNo){
     …
     rollNo = aRollNo;
}

 


01.3.     Inline Functions

·         Inline functions is a way used by compilers to improve efficiency of the program, when functions are declared inline normal process of function calling (using stack) is not followed instead function code is added by compiler  at all points where these functions have been called. Basic concept behind inline functions is that they are functions in our code but in compiler generated files these functions code is added by compiler at all places where they were called in the code.
·         Normally small size functions that need to be called many times during program execution are declared inline. Inline functions decrease the code execution time because program in their case doesn’t involve function call overhead.
·         Keyword ‘inline’ is used to request compiler to make a function inline.
·         However using inline keyword with function doesn’t guarantee that function will definitely in inlined, it depends on the compiler if it finds it can make function inline it does so otherwise it ignores the keyword inline and treat the function as normal function.


Example

inline int Area(int len, int hi)

{
     return len * hi;
}
int main()
{
     cout << Area(10,20);
}


Inline Functions

The functions defined inside the class are by default inline (whether we mention keyword inline with them or not)
In case we define function outside the class then we must use the keyword ‘inline’ to make the function inline.
However compiler decides whether it will implement these functions code as inline or not.

 



Example
Inline function inside the class:

class Student{
     int rollNo;
public:
     void setRollNo(int aRollNo){
           …
           rollNo = aRollNo;
     }
};

Example
Inline function outside the class:

class Student{
     …
     public:
     inline void setRollNo(int aRollNo);
};
void Student::setRollNo(int aRollNo){
     …
     rollNo = aRollNo;
}
class Student{
     …
     public:
     void setRollNo(int aRollNo);
};
inline void Student::setRollNo(int   aRollNo){
     …
     rollNo = aRollNo;
}
class Student{
     …
     public:
     inline void setRollNo(int aRollNo);
};
inline void Student::setRollNo(int                                   aRollNo){
     …
     rollNo = aRollNo;
}

01.4.     Constructor

Constructor is used to initialize the objects of a class. Constructor is used to ensure that object is in well defined state at the time of creation.
The constructor of a class is automatically generated by compiler however we can write it by our self also.
Constructor is automatically called when the object is created. Constructors are not usually called explicitly by us.

01.5.     Constructor Properties

          Constructor is a special function having same name as the class name
          Constructor does not have return type
          Constructors are commonly public members

 


Example
class Student{
            int rollNo;
public:
            Student(){
                        rollNo = 0;
           
            }
};

int main()
{
            Student aStudent;
            /*constructor is implicitly called at this point*/
}

We can assure that constructor is called automatically by adding cout statement in constructor as shown below,

#include <iostream>
using namespace std;

 


class Student{
            int rollNo;
public:
            Student(){
                        rollNo = 0;
                        cout<<”I am constructor of Student class…\n”;
            }
};

int main()
{
            Student aStudent;
            /*constructor is implicitly called at this point*/
system(“pause”);
return 0;
}

01.6.     Default Constructor

          Constructor without any parameter or with all parameters with default values is called default constructor
          If we do not define a default constructor the compiler will generate a default constructor
          Compiler generated default constructor is called implicit and user written default constructor is called explicit
          This compiler generated default constructor initialize the data members to their default values
          If we have given any constructor for a class whether it is
          our own explcit default constructor ( i.e parameterless or with parameters having default values )
       or
          our own constructor with parameters

Then compiler will not create implicit default constructor[1].

Example

Consider the class student below it has no constructor so compiler will generate one for it,

class Student
{
            int rollNo;
            char *name;
            float GPA;
public:
            …                    //no constructors
};


Code of Compiler generated implicit default constructor

{
            rollNo = 0;
            GPA = 0.0;
            name = NULL;
}


01.7.     Constructor Overloading

We can write constructors with parameters as well. These parameters are used to initialize the data members with user supplied data (passed as parameter). The example is shown below, here example Student class has four constructors their prototypes are,

  1. Student();  /* explicit default parameterless constructor */
  2. Student(char * aName);  /* constructor with one parameter* /
  3. Student(char * aName, int aRollNo);  /* constructor with two parameters */
  4. Student(int aRollNo, int aRollNo, float aGPA);  /* constructor with three parameters */

Example

class Student{
            int rollNo;
            char *name;
            float GPA;
public:
            Student();  /* explicit default constructor */
            Student(char * aName);  /* constructor with one parameter* /
            Student(char * aName, int aRollNo);  /* constructor with two parameters */
            Student(int aRollNo, int aRollNo, float aGPA);  /* constructor with three parameters */

};
Student::Student(){

            rollNo = 0;
            name = NULL; // to indicate it is pointing to nothing at this moment otherwise it can generate erroneous code.
            GPA = 0.0;

}
Student::Student(int aRollNo){

            if(aRollNo < 0){
                        rollNo = 0;
            }
            else {
            rollNo = aRollNo;
            }
name = NULL;
           
}
Student::Student(int aRollNo,
                                                char * aName){

            if(aRollNo < 0){
                        rollNo = 0;
            }
            else {
            rollNo = aRollNo;
            }
           
  if (strlen(aName) > 0)
                                    {
             name = new char[strlen(aName)+1];
                 strcpy(name,aName);
                                      }
  else
           {
name = NULL;
}

}


We can create this Student class object using any one of these constructors as follows,

int main()
{
            Student student1;  // default constructor will be used
            Student student2(“Name”); // one parameter constructor will be used
            Student student3(”Name”, 1);  // two parameter constructor will be used
            Student student4(”Name”,1,4.0); // three parameter constructor will be used
}


01.8.     Constructor Overloading

We can use default parameter values to reduce the writing effort in that case we will have to write only one constructor and it will serve the purpose of all constructors as given below,

Example
Student::Student(       char * aName = NULL,  int aRollNo= 0,  float aGPA = 0.0) {

}


It is equivalent to all three constructors,

Student();
Student(char * aName);
Student(char * aName, int aRollNo);
Student(char * Name, int aRollNo, float aGPA);

It will use default values if values are not passed as arguments while creating objects) it is described in code given below,

int main()
{
        Student student1;  /*char * aName = NULL,  int aRollNo= 0, float aGPA = 0.0*/

        Student student2( “Name” );  /*char * aName = Name, int aRollNo= 0, float aGPA = 0.0*/

        Student student3( ”Name”,  1 );   /*char * aName = Name, int aRollNo= 1, float aGPA = 0.0*/

        Student student4( ”Name”, 1 , 4.0);  /*char * aName = Name, int aRollNo= 1, float aGPA = 4.0*/


}


Copy constructors are used when:

          Initializing an object at the time of creation (we want to create an object with state of a pre existing object)
          When an object is passed by value to a function (As you know temporary copy of object is created on stack so we need copy constructor to create that temporary object with the state of actual object being passed).


Example
void func1(Student student){
}







int main(){

            Student studentA;
            Student studentB = studentA;

            func1(studentA);

}



Copy Constructor (Syntax)

Student::Student( const Student &obj){
           
     /*copying values to newly created object*/
    rollNo = obj.rollNo;
            name = obj.name;
            GPA = obj.GPA;

}



As was the case with default constructor compiler also generates copy constructor by itself however we can override that copy constructor by writing our own copy constructor as shown in example below,

#include <iostream>
using namespace std;

class Student{

            int rollNo;
public:
            Student(){
                        rollNo = 0;
                        cout<<”I am default constructor of Student class…\n”;
            }

Student(const Student &obj){
             cout<<”I am copy constructor of Student class\n”;

   rollNo = obj.rollNo;
             
}
};

int main()
{
            Student aStudent;
            /*default constructor is implicitly called at this point*/

            Student bStudent = aStudent;
            /*copy constructor is implicitly called at this point*/

system(“pause”);
return 0;
}




01.10. Shallow Copy

          When we initialize one object with another then the compiler copies state of one object to the other using copy constructor by assigning data member values of previous object to newly created object.

Shallow copy using default Copy Constructor (Syntax)
Student::Student(       const Student & obj ){

            rollNo = obj.rollNo;
            name = obj.name;
            GPA = obj.GPA;
}


          This kind of copying is called shallow copying

Example

Student studentA;
Student studentB = studentA;  /*Shallow copy: compiler will use copy constructor to assign studentA values to newly created object studentB*/



Shallow copy works fine if our class doesn’t include dynamic memory allocation but in case of dynamic memory allocation it leads to dangling pointer problem as explained below,

Problem is Shallow Copy

Student class data member name of char * type is added to store the name of student and it is using dynamic memory according to the length of name entered by user for student.




Object studentB is also pointing to memory allocated object studentA for Student class data member name of char * type, now there are two problems with this sort of copying,

Suppose we delete first object studentA for some reason then its destructor will also free memory allocated by it hence memory area containing name “AHMAD” will also be freed and will be given to some other application by operating system, but studentB member name is still pointing to that area so issue of “Dangling Pointer” will arose. [Pointer pointing to incorrect memory location]. If we will try to print the name of object studentB our program will terminate abnormally as it was pointing memory of some other applications.
Secondly if for some reason we change name of studentA the value of object studentB will also be changed as it pointing to same memory location.

We resolve these two issues using deep copy.


01.11. Deep Copy
We write our own deep copy code in copy constructor so that when we create new object from an existing object using copy constructor we also allocate new dynamic memory for data members involving dynamic memory as shown below,
Student::Student( const Student & obj){

            int len = strlen(obj.name);
            name = new char[len+1];
             // assignming new dynamic memory to data member name of char * type for newly created object*/
            strcpy(name, obj.name);
            …
            //copy rest of the data members in the same way
}


Example

Student studentA;
Student studentB = studentA; // now copy constructor will perform deep copy (separate memory for both objects)






In case our class doesn’t involve dynamic memory then default copy constructor that performs shallow copy works fine.
In case our class has any data member involving dynamic memory we have to write our own code to do deep copy.
  compiler generated default constructor is called implicit and user written default constructor is called explicit

Post a Comment

Don't Forget To Join My FB Group VU Vicky
THANK YOU :)

Previous Post Next Post