The best programs are written so that computing machines can perform them quickly and so that human beings can understand them clearly. A programmer is ideally an essayist who works with traditional aesthetic and literary forms as
well as mathematical concepts, to communicate the way that an algorithm works and to convince a reader that the results will be correct. Donald E. Knuth

Classes and Objects

Introduction to Classes and Objects
C++ language extends C language with OOP concept. Classes and Objects actually implement the OOP feature in C++. Class is an extension to the idea of structures. It is a user defined data type and objects are the variables of class data type.
Let's look at a simple program which illustrates how to define classes and objects in C++ :



#include<iostream>
using namespace std;

/* define a student class with necessary data members and functions */
class student {
   /* declare the data members of the class */
   int roll;
   float percent;
public :
   student() { } // constructor  
   /* declare the member functions */
   void inputData();
   void displayData();
};

/******************* Define the member functions ****************************/

/* inputs data from user */
void student :: inputData() {
   cout << "Enter Roll No. : ";
   cin >> roll;
   cout << "Enter Percentage : ";
   cin >> percent;
}

/* displays student data */
void student :: displayData() {
   cout << "Roll No. : " << roll << "\tPercentage : " << percent << endl;
}

/****************************************************************************/

int main() {
   student s1, s2; // declare objects 's1' and 's2' of class 'student'
   s1.inputData(); // call the function inputData() to input 1st student's data
   s2.inputData(); // input 2nd student's data
   cout << "\nYou have entered the following data :- " << endl;
   s1.displayData(); // display 1st student's data
   s2.displayData(); // display 2nd student's data
   return 0;
}
Run this program in your system to take input at run-time  

This program does a very simple task of taking 2 student's roll no. and percentage and then displays them.
First we define a class student with data members roll and percent. We also declare two member functions inputData( ) and displayData( ) which operate on data members. Thus, we see that data and functions related to an entity student is wrapped in a class. This is nothing but encapsulation.
Then, we define the operation of the member functions outside the class ( please note the syntax ). So, a class student is completely ready to be used as a data type.
Now, we declare two objects s1 and s2 of type student. Each of these objects have their own copy of the data members. So, memory for data members are allocated when objects are created. Memory for member function is allocated when they are defined.
Finally, we take input and display data of two students using the respective objects and dot ( . ) operator.
In the program, we declared a constructor which will be discussed in the next section on
Constructors and Destructors. There is one more keyword public used in the program. This is described below.
Following diagram shows the representation of the class student and the two objects s1 and s2 :

ClassObjects

student
roll, percent
inputData()
displayData()
s1 s2
roll = 3
percent = 87.39
roll = 7
percent = 75.43

Access Specifiers
The keyword public used in the above program is an access specifier which specifies that the members ( data or functions ) declared after the public keyword are accessible outside the class or more precisely they can be accessed directly by an object of that class. Public members of the class student are inputData( ) and displayData( ).
The keyword private can be used to hide some members of the class i.e they are not accessible outside the class or the object cannot access them directly. They can be accessed only by the member functions of the class. By default, all the members of a class are private until an access specifier is used. In the above program, data members roll and percent are private and cannot be accessed directly by s1 or s2 using the dot ( . ) operator. This process of hiding the data is nothing but data abstraction.
The keyword protected is another access specifier which is similar to private but protected members of a base class can be accessed in derived class. We will elaborate this in the section on Inheritance.
Following program elaborates the concept of access specifiers :

#include<iostream>
using namespace std;

// define a class to store movie information
class X {
public :
   int a; // public member, can be accessed with an object
private :
   // private member, accessed by member functions of class 'X' only
   // can't be accessed by an object
   int b;
protected :
   // private member, accessed by member functions of class 'X' and
   // child class 'Y' but can't be accessed by an object
   int c;
};

// define a class 'Y' which is derived from 'X'
class Y : public X {
public :
   void setVar() {
      a = 12; // valid statement as 'a' is inherited from 'X'
      // b = 17; // invalid as 'b' is not inherited
      c = 13; // valid as 'c' is inherited and visible
   }
};

int main() {
   X xobj; // declare an object of class 'X'
   xobj.a = 5; // valid statement since 'a' is public member
   // xobj.b = 7; // invalid as 'b' is private
   // xobj.c = 3; // invalid as 'c' is protected
   Y yobj; // declare an object of class 'Y'
   yobj.setVar(); // calling a member function of class 'Y'
   return 0;
}


Inline Member Functions
Making a member function inline improves the performance of a C++ program. If keyword inline is placed before a function, compiler substitutes the function call with the function definition at compile time. Thus, there is no overhead of calling the function at runtime. A function which is defined inside the class is inline even without the use of inline keyword. Following keyword illustrates the use of inline functions :

#include<iostream>
using namespace std;

class X {
   int x, y;
public :
   void setVal(int, int);
   /* inline function since it is defined inside the class though
           the keyword 'inline' is not used */
   int getMax() {
      return ( x > y ) ? x : y;
   }
   /* inline function but the defination is outside the class */
   inline int getMin();
};

void X :: setVal(int a, int b) {
   x = a;
   y = b;
}

int X :: getMin() {
   return ( x < y ) ? x : y;
}

int main() {
   X obj; // declare an object 'obj' of class 'X'
   int max, min;
   obj.setVal(5, 7);
   max = obj.getMax();
   cout << "Max value : " << max << endl;
   obj.setVal(2, 4);
   min = obj.getMin();
   cout << "Min value : " << min << endl;
   return 0;
}


Friend Functions
We have seen that private members can be accessed only by the member functions of the class and they are not visible outside the class. However, a friend function can access the private members outside the class. A friend function is not a member of a class even though it is declared inside the class. See the program below :

#include<iostream>
using namespace std;

class rectangle {
   int length, breadth;
public :
   void setDimension(int l, int b);
   /* a friend function to print the area, it takes an object of
      'rectangle' class as its argument */
   friend void printArea(rectangle rect);
};

/* setDimension is a member function */
void rectangle :: setDimension(int l, int b) {
   length = l;
   breadth = b;
}

/* printArea is a friend function 
   'classname :: ' is not used before the function name 
*/
void printArea(rectangle rect) {
   /* length and breadth can be directly accessed even though 
      they are private */
   int area = rect.length * rect.breadth;
   cout << "Area : " << area << endl;
}

int main() {
   rectangle r;
   r.setDimension(9, 7);
   // call friend function with object 'r' as argument 
   printArea(r);
   return 0;
}

Please note that a function can be declared as friend to any number of classes. It is particularly useful when we would like to define a common function which operates on objects of two or more classes.

Static Members of a class
An object of a class contains it's own copy of the data members. If a data member is declared as static, then only one copy of that member is created which is common to all objects. A static data member cannot be initialized inside the class ( non-static data members can be initialized in constructors ) but can be initialized outside the class. Static data members are also known as class variables and are used to maintain values common to the entire class.
A static member function has access to only other static members ( data or functions ) and they can be called even if no object of the class is created. They are called using class names ( instead of objects ).
Following program illustrates the behaviour of static members :

#include<iostream>
using namespace std;

class X {
   int i;
   static int obj_count;
public:
   //static int obj_count;
   X() { // constructor
      obj_count++;
      i = 0;
   }
   void func1() { } // do-nothing function
   static void func2() { } // do-nothing function
   static int getObjectCount() {
      // i = obj_count; // invalid statement since 'i' is not static
      // func1(); // invalid since func1() is not static
      func2(); // valid since func2() is static 
      return obj_count; // valid since 'obj_count' is static
   }
};

int X :: obj_count = 0; // initialize the static member

int main() {
   int no_of_objects;
   no_of_objects = X :: getObjectCount(); // no objects are created yet 
   cout << "Objects created : " << no_of_objects << endl;
   X obj1, obj2; // two objects are created
   no_of_objects = X :: getObjectCount();
   cout << "Objects created : " << no_of_objects << endl;
   return 0;
}


Array of Objects
Similar to array of structures, we can declare an array of objects. Suppose, we have a class book, we can store information about ' n ' books using an array of ' n ' objects of type book. See the program below :

#include<iostream>
#include<string>
using namespace std;

/* define a class which encapsulates the data members related to
 * entity 'book' and the functions which operate on data members
*/
class book {
   string name;
   float price;
public :
   void setBookInfo(string, float);
   void getBookInfo();
};

void book :: setBookInfo(string b_name, float b_price) {
   name = b_name;
   price = b_price;
}

void book :: getBookInfo() {
   cout << "Name : " << name << "\tPrice : " << price << endl;
}

int main() {
   int i;
   book b[3]; // array of 'book' objects to store info about 3 books
   // set information of three books
   b[0].setBookInfo("Three Mistakes of My Life", 299.50);
   b[1].setBookInfo("Christmas Carol", 199.0);
   b[2].setBookInfo("Wake up Intellectuals", 89.75);
   // display book information
   for ( i = 0; i < 3; i++ ) { // iterate over the 'book' objects
      b[i].getBookInfo();
   }
   return 0;
}


Nesting of Classes
We can define a class as a data member of another class. This is known as nesting. However a better approach to C++ code design is to define the classes independently and declare an object of one class as a data member of another class whenever required. This approach reflects a ' part-of ' relationship between two entities. Suppose there are two classes, car and wheel. Since wheel is a part-of car, we can declare an object of type wheel as a data member of class car. Following program illustrates the relation :

#include<iostream>
using namespace std;

/* define a class 'wheel' */
class wheel {
   float radius;
public :
   void setRadius(float r) {
      radius = r;
   }
   float getRadius() {
      return radius;
   }
};

/* define a class 'car' and declare an object of class 'wheel' as one of
   its data member */
class car {
   int model_no;
   string color;
   wheel w; // declare an object of 'wheel' type
public:
   void setCarInfo(int car_model, string car_color, float wheel_radius) {
      model_no = car_model;
      color = car_color;
      w.setRadius(wheel_radius);
   }
   void getCarInfo() {
      cout << "Model : " << model_no << endl;
      cout << "Color : " << color << endl;
      cout << "Wheel Radius : " << w.getRadius() << endl;
   }
};

int main() {
   /* declare an object of type 'car'
      object of type 'wheel' is automatically declared */
   car c;
   c.setCarInfo(7188, "red", 103.76);
   c.getCarInfo();
   return 0;
}


Pointer to Object
A pointer variable can hold the address of an object ( an object is a variable of type class ) and then public members of the class can be accessed using the pointer variable ( instead of objects ) and the arrow ( -> ) operator. Following program illustrates the concept of pointer to an object :

#include<iostream>
using namespace std;

class square {
   int size;
public :
   void setSize(int s) {
      size = s;
   }
   int getArea() {
      return (size * size);
   }
};

int main() {
   square sq; // declare an object of type 'square'
   square *ptr; // pointer variable of type 'square'
   ptr = &sq;
   ptr->setSize(7); // set the size of the square
   int area = ptr->getArea(); // get area of the square
   cout << "Area : " << area << endl;
   return 0;
}


this Pointer
this pointer points to an object ( holds the address of the object ) which is currently invoking a member function of the class. Thus, inside a member function, this pointer may be used to refer to the object which invoked the function. See the program below :

#include<iostream>
using namespace std;

class rectangle {
   int length, breadth;
public :
   void setDimension(int l, int b) {
      length = l;
      breadth = b;
   }
   int getArea() {
      return (length * breadth);
   }
   /* compare the area of two rectangles 
    * returns true if the area of invoking rectangle object
    * is greater than area of object passed as parameter
         */
   bool compare(rectangle rect) {
      int area_rect1 = this->getArea(); // area of rect1
      int area_rect2 = rect.getArea();  // area of rect2
      if ( area_rect1 > area_rect2 ) {
         return true;
      }
      return false;
   }
};

int main() {
   rectangle rect1, rect2;
   rect1.setDimension(7, 8);
   rect2.setDimension(6, 9);
   /* rect1 is invoking the function compare()
     'this' pointer points to object 'rect1' */
   if (rect1.compare(rect2)) {
      cout << "Rectangle 1 has larger area " << endl;
   }
   else {
      cout << "Rectangle 2 has larger area " << endl;
   }
   return 0;
}

Back | Next