Classes And Objects In C++

A Brief Introduction To Classes And Objects In C++.

Classes and objects are the building blocks of Object-oriented programming in C++. Every entity, living or non-living can be represented as an object and programmed accordingly using C++. Thus entities like a car, desk, person, bird, animal, etc. can be represented as objects.

Class is a level higher than the object and represents the category of objects. Thus, class acts as a blueprint that outlines the object design and details. This includes data that is used to describe the object and various methods or functions that can act on the object data.

=> Watch Out The Simple C++ Training Series Here.

In this tutorial, we discuss all the details of class and objects in C++ along with their programmatic representation.

Classes and Objects in C++

Classes

A class in C++ can be viewed as a blueprint or a skeleton of a particular entity. Class is a user-defined data type. It contains the general information or data for that particular entity and the functions that operate on that entity.

In C++ syntax, we define a class with keyword “class” followed by the name of the class.

The class name is followed by the details of the class enclosed in curly braces and is terminated by a semicolon.

The following block shows the general syntax for the class definition.

General Syntax of Classes

As shown in the above representation, the class can have access specifiers like public/protected/private. It can have data members and member functions. The data and functions are called as members of the class. By default, the members are private to the class, so that no outside entity has access to these members.

For Example, a vehicle can be a generalized class having properties like a model, color, chassis No., average_speed, etc. It can have functions like changeModel, accelerate, slowdown, etc. that perform actions on the data members. We can define a class named “vehicle” that will have all these data members and functions.

As already mentioned, a class is just a blueprint for the entities. It doesn’t take any space in memory when it’s defined. For a class to be functional, we have to define objects that can make use of the members of the class.

Objects

In order to use the class functionality, we need to instantiate the class to create an object. An object is an instance of a class. I simple words, we can say that an object is a variable of type class.

The general syntax to create an object is:

classname object_name;

Once the object is created, it can be used to access the data members and functions of that class.

Accessing the members of the class (data and functions) is done using the dot (.) operator, which is also called as the member access operator.

If obj is the name of the object and there is a function “display ()” in the class, then the function can be accessed as “obj.display ()”.

However, there is a catch in the above statement. We can access the function display () using an object and the dot operator if the function is “public”.

Access Specifiers

In C++, accessing the data members and functions in the class depends on the access given to that particular data member or function using an access specifier.

C++ supports the following access specifiers:

#1) Private

This is the default access specifier for a class in C++. This means that if no access specifier is specified for the members in a class, then it is considered private.

When a member is private, it cannot be accessed outside the class. Not even using the object and the dot operator. The private data members can only be accessed using the member functions of the class.

However, there is an exception to this rule, which we will discuss in our later topics.

#2) Public

A data member or function that is defined as public in the class is accessible to everyone outside the class. These members can be accessed using the object and the dot operator.

#3) Protected

A protected member of a class is accessible to the class itself and the child classes of that class.

This access specifier is especially used in case of inheritance and we will discuss this in detail while discussing the inheritance topic.

Let us take the following example to better understand these access specifiers.

#include <iostream>
#include <string>
using namespace std;
class ABC{
int var1 = 10;
public:
string name;
void display()
   {
      cout<<"var1 ="<<var1<<endl;
      cout<<"name ="<<name<<endl;
   }
};
int main();
   {
      ABC abc;
      //abc.var1 = 20;
      abc.name = "sth";
      abc.display();
}

Output:

var1 =10
name =sth

In this program, we have two data members out of which var1 of type int is private (access specifier not specified. Default is private). Another member is the string name, which is declared as public. We have yet another function display which displays the value of both these members.

In the main function, we declare an object abc of class ABC. Then we set values to data members and also the call function display using object ‘abc’.

However, when the compiler encounters the line abc.var1 = 20; it will generate an error that “var1 is private variable”.

This is because we cannot access private data members of a class outside the class. Thus there is an error. But we can access it inside the function and therefore when we output the value of var1 in the display function; it does not throw any error.

Hence the output of the program displays the initial value with which var1 is declared.

So far, we have seen the details about classes, object, and access specifiers, now let us take up a complete example of a sample class student. This class has data members: student_id, student_name, and student_age. It also has member functions to read student info and display student info.

In order to make things easy for the readers, we have declared all members of the class as public.

The following program shows the complete implementation.

#include <iostream>
#include <string>
using namespace std;
class student{
   public:
   int student_id;
   string student_name;
   int student_age;
  
   void read_studentInfo();
   void print_studentInfo() {
      cout<<"\nStudent ID : "<<student_id<<endl;
      cout<<"Student name : "<<student_name<<endl;
      cout<<"Student Age : "<<student_age;
   }
};
void student::read_studentInfo(){
   cout<<"Enter Student Id :"; cin>>student_id;
   cout<<"\nEnter student_name :"; cin>>student_name;
   cout<<"\nEnter student_age :"; cin>>student_age;
}
 
int main()
{
   student s1;
   s1.read_studentInfo();
   s1.print_studentInfo();
}

Output:

Enter Student Id :1

Enter student_name :abc

Enter student_age :12

Student ID : 1
Student name : abc
Student Age : 12

Thus, we have a complete class defined above. The only notable difference is that we have defined one function “print_studentInfo” inside the class whereas other function “read_studentinfo” is defined outside the class. These are the two ways in which member functions can be defined for a class.

Note that the function that is defined outside still has a declaration/prototype inside the class. Also, it is defined outside the class using the scope resolution operator (::). Then in the main function, we create a student class object and then we call functions to read and display the data.

Constructors

So far in this tutorial, we have created a simple object and then we assign values to each data member of the class in the main function after reading these values from the standard input.

In this topic, we will take a look at a special function that is used to initialize the object during its creation. This special function is called a constructor.

A constructor is a member function of the class but it differs from the normal member function in the following ways:

  1. The constructor has no return value i.e. constructor never returns a value.
  2. It is a public member function of the class.
  3. It is used to initialize the data members and construct the object of the class.
  4. It is automatically called by the compiler when the object is being created.

Types of Constructors

C++ supports the following types of constructors.

#1) Default Constructor

A default constructor is the basic constructor and has no parameters. We can create a simple object without any parameters using the default constructor.

Default constructor has the following syntax:

classname()
{
                 //constructor code
}

If a class does not have a default constructor then the compiler creates it.

#2) Parameterized Constructor

A parameterized constructor is one that has a parameter list using which we can initialize the class members. When we declare an object in a parameterized constructor, then we need to pass initial values to the constructor function as parameters.

A parameterized constructor function looks as shown below.

classname(argument list){
                //constructor code
}

A parameterized constructor is used to overload constructors. We will see more about overloading in our later topics.

A parameterized constructor is used for the purpose of initializing data members of different objects. While doing so, we can pass different values of data members to different objects.

#3) Copy Constructors

C++ supports a third type of constructor known as Copy constructor. Its general form is

classname (const classname& obj);

As shown in the above declaration, in copy constructor a new object is created using the values of another object of the same class. The parameter that is passed to the constructor is the constant reference of an object whose values will be used for the construction of the new object.

A copy constructor is usually called in the following situations:

  1. When a class object is returned by value.
  2. When an object is passed to a function as an argument and is passed by value.
  3. When an object is constructed from another object of the same class.
  4. When a temporary object is generated by the compiler.

However, we cannot guarantee that copy constructor will surely be called in all the above cases as C++ compiler has a way to optimize copy operations.

A copy constructor carries out memberwise copy between objects. Just like default constructor, C++ compiler creates a default copy constructor if we do not provide one in our program. But when a class has certain data members like pointers, references or any runtime allocation of resources, then we need to have our own user-defined copy constructor.

The reason is that default copy constructor performs only a shallow copy of data members i.e. both objects will share the same memory location. This is fine for simple non-pointer data members.

However, when it comes to pointers or any other dynamic data members we would like the data to be pointed to a new memory location. This is the deep copy and can be achieved only using a user-defined copy constructor.

Given below a complete C++ program that implements all three types of constructors and their usage in constructing an object.

#include <iostream>
#include <string>
using namespace std;
class student{
 public:
   int student_id;
   string student_name;
   int student_age;
   //default constructor
   student(){
      student_id = 1;
      student_name = "abc";
      student_age = 10;
}
//parameterized constructor
student(int id,string name,int age){
   student_id = id;
   student_name = name;
   student_age = age;
}
//copy constructor
student(const student& st){
   student_id = st.student_id;
   student_name = st.student_name;
   student_age = st.student_age;
}
 
void print_studentInfo()
{
   cout<<"\nStudent ID : "<<student_id<<endl;
   cout<<"Student name : "<<student_name<<endl;
   cout<<"Student Age : "<<student_age<<endl;
  }
};
int main()
{
   student s;
   cout<<"********** s **********";
   s.print_studentInfo();
   student s1(2,"xyz",12);
   cout<<endl;
   cout<<"********** s2 **********";
   student s2 = s1; //copy constructor
   s2.print_studentInfo();
}

Output:

********** s **********
Student ID : 1
Student name : abc
Student Age : 10

********** s2 **********
Student ID : 2
Student name : xyz
Student Age : 12

The screenshot for the same is given below. 

constructors output

In this program, we have defined a class student which similar to one defined in the previous program. The difference is that instead of reading data member values from standard input through a function, we define three constructors.

It is absolutely possible for a class to have more than one constructor. We have a default constructor that initializes the data members to initial values. Next, we define a parameterized constructor that passes initial values as parameters to the constructor.

Next, we define a copy constructor to which we pass a constant reference to an object of the student class.

In the main function, we create three objects separately using three constructors. First object s is created using the default constructor. Second object s1 is created using the parameterized constructor while the third object s2 is created using a copy constructor.

Note the creation of the third object s2. Here we assign the already created object s1 to the new object s2. Thus when we construct a new object using the already existing object, a copy constructor is called by the compiler.

Assignment Operator

We can also assign the values of one object to another using an assignment operator (=). In this case, we will have a statement like s1 = s.

The difference between copy constructor and assignment operator is that while the copy constructor constructs altogether a new object, the assignment operator just assigns the values of a member of the object on RHS to that of the object on LHS. This means that the objects on both the sides of an assignment operator need to be existing prior to assignment.

Destructors

A destructor is also a special function like a constructor but it implements the functionality that is exactly opposite to the constructor. While constructor is used to create an object, a destructor is used to destroy or delete an object.

Some of the characteristics of the destructor include:

  • A destructor name is the same as the classname but begins with a tilde (~) sign.
  • Destructor has no return type.
  • A destructor has no arguments.
  • There can be only one destructor in a class.
  • The compiler always creates a default destructor if we fail to provide one for a class.

The general syntax of a destructor is:

~classname(){
                    //cleanup code
 }

The destructor of a class is usually called in the following situations:

  1. When the object goes out of the scope, then the class destructor is automatically called.
  2. Similarly, the destructor is called when the program finishes execution. This means that all objects also cease to exist. Hence, the destructor of each object will be called.
  3. The destructor of the class is also called when the ‘delete’ operator to delete an object is executed.
  4. We can also call the destructor explicitly to carry out any cleanup activities after we are done with the object functionality.

The example given below demonstrates the working of a destructor.

#include <iostream>
using namespace std;
class sample{
public:
   sample(){
   cout<<"Constructor::sample called"<<endl<<endl;
}
 
   ~sample(){
   cout<<"Destructor::~sample called"<<endl;
}
 
void display(){
   cout<<"This is sample class"<<endl<<endl;
   }
};
int main(){
 
   sample obj;
 
   obj.display();
   return 0;
}

Output:

Constructor::sample called

This is sample class

Destructor::~sample called

The screenshot for the above output is given below.

destructor output

We have defined a class sample in which we have defined a constructor, a destructor and a function display. In the main function, we create an object obj of class sample and then call the display function on this object.

After that, a return 0 is executed. In the output, we can see that the moment when the display function returns and the program control comes to statement return 0, the destructor is executed. This means that it is executed the moment when the object goes out of the scope.

“this” Pointer

C++ uses a special concept related to the objects, which is known as “this” pointer. The “this” pointer always points to the current object. Thus depending on the situation, whenever we have to refer to the current object, we use “this” pointer.

We know that every time when an instance of the class i.e. an object is created, a separate copy of the data members of the class is made for the object. But when it comes to the member functions of the class, all objects share the same copy.

So when one or more objects access the member functions simultaneously, then how do we ensure that proper data members are accessed and modified by the member functions?

This is the place where “this” pointer comes into action. The compiler passes an implicit pointer with the function name as “this”. This is called the “this” pointer.

The “this” pointer is passed as a hidden argument to all the member function calls. It is usually a local variable. Hence, “this” pointer is a constant pointer and its contents are the memory address of the current object.

Note that this pointer is available only for non-static member functions and not for static functions. This is because the static functions need not be accessed using an object. They can be directly accessed using the classname.

We usually use the “this” pointer in situations where the member variables and the parameters are passed to initialize the member variables that share the same name. We also use it when we need to return the current object from the function.

Let us see the demonstration of “this” pointer below.

#include <iostream>
using namespace std;
class Sample {
private:
   int num;
   char ch;
public:
   Sample &setParam(int num, char ch){
      this->num =num;
      this->ch = ch;
      return *this;
   }
void printValues(){
   cout<<"num = "<<num<<endl;
   cout<<"ch = "<<ch;
   }
};
int main(){
   Sample obj;
 
   obj.setParam(100, 'A');
   obj.printValues();
   return 0;
}

Output:

num = 100
ch = A

In the above program, we have a class called Sample, with two data members’ num and ch. We have a member function setParam that passes the parameters with the same names, num, and ch to set the values of the member variables.

Inside the function, we assign these values to the current object member variables indicated by this pointer. Once the values are set, the current object “this” is returned from the function.

In the main function, we first create an object of Sample class, obj and call a setParam function to set the values and then call the printValues function to print the values.

Conclusion

We have learned the basic building blocks of OOP in C++ in this tutorial. Understanding the classes and objects are the primary requirements, to begin with, OOP in C++. We have also learned about the constructors and destructors in detail with examples.

In our upcoming tutorial, we will learn about the initializer lists in C++.

=> Watch Out The Simple C++ Training Series Here.