OOPS Concepts in C++ with Examples

In this article, we will discuss the OOPS concepts in C++. We will discuss what is OOPS, what classes and objects in OOPS are, and the 4 pillars of OOPS in C++. So, let’s get started by learning what is Object-Oriented Programming.

What is OOPS?

The programming paradigm known as "Object-Oriented Programming" works with objects and classes. In a subsequent section of this article, we will talk about objects and classes. For the time being, we can state that object-oriented programming is a style of programming that, by emphasizing real-world elements (called objects), greatly simplifies programming.

Object-Oriented Programming has 4 main Pillars. They are as follows.

  1. Inheritance
  2. Polymorphism
  3. Abstraction
  4. Encapsulation

We will study the implementation of each of these OOPS pillars in C++ in great detail in further sections. First, let us start by studying what are classes and objects.

OOPS Concepts in C++ with Examples

First, let us start by studying what are classes and objects.

Objects

An object is an instance of a Class. This is the formal definition of an Object. However, let us talk about the actual meaning of an object first as we don’t know what a Class is for now. An object is a real-world entity. It has states i.e. its properties and behaviors i.e. its functions.

We could claim, for example, that a car is an object. This is due to the states (properties) that it will have, such as the model name, brand name, color, and type (SUV or Sidan, etc.). Additionally, it will perform actions like speeding up (a car can speed up), braking (when stopping), etc.

A pen is yet another example of an object. It has states describing its color, brand, etc. It has functions like writing, scribbling, etc.

Classes

A Class is a blueprint of an Object. It will tell us what properties an object will have and what functions it can perform. However, the values of those properties can vary from object to object. For instance, a Car is a class that may have properties like color, brand name, model name, etc. Now, there can be a car whose name is “Swift” whose brand name is “Maruti Suzuki” and whose color is “Grey”. Also, there can be another car whose model name is “Polo” and the brand name is “Volkswagen” and whose color is “Red.”

A Class is a collection of properties (or states, like size, color, etc.) and behavior (or functions, like writing, reading, walking, talking, etc.).

The different objects have varying values for these attributes, and all of them or some of them carry out some or all of the functions listed in a class.

Now that we know what Classes and Objects are, let us now create a Class and its Objects.

How to Create a Class and its Objects in C++

Consider the program shown below.

Class and Object Example Program

// Default argument
#include <bits/stdc++.h>
class Student {  
    public:    
    string name;
    int roll_no;
    int marks;
    void setData(string name,int roll_no, int marks) {
        this->name = name;
        this->roll_no = roll_no;
        this-> marks = marks;
    }
        void printData() {
        cout<<"My name is "<<name<<" and my roll number is "<<roll_no<<". I got "<<marks<<" marks out of 100\n";
    }
    
};
int main() {
    // s1 is an object of class Student
    Student s1;
    s1.setData("Guneet",2,95);
    s1.printData();
}

So, in the program above, a class Student is created that has these 3 data members: name, marks, and roll_no. Also, it has functions called member functions in C++. The functions are setData() and printData().

So, now that we have understood how to create Classes and Objects in C++, let us move to Constructors in C++.

Constructors in OOPS in C++

A constructor is a function inside the class that has the same name as that of the class. It is used to initialize the objects in C++. Consider the Program written below.

Program to show Constructor Example

#include <bits/stdc++.h>
class Student {
  
    public:
    
    string name;
    int roll_no;
    int marks;
    
    Student() {
        cout<<"Student Class Constructor called\n";
    }
    
    void setData(string name,int roll_no, int marks) {
        this->name = name;
        this->roll_no = roll_no;
        this-> marks = marks;
    }
    
    void printData() {
        cout<<"My name is "<<name<<" and my roll number is "<<roll_no<<". I got "<<marks<<" marks out of 100\n";
    }
    
};

int main() {
    
    Student s1; //constructor will be called automatically because a new object is created.
    s1.setData("Guneet",2,95);
    s1.printData();
}

As you can see, the constructor is automatically called when an object is created. As you can see, the constructor does not have any return type also.

A constructor must always be placed in the public section of the class. This is because when the object is created and the constructor gets called, it is then that the memory gets allocated to the object. So, if the constructor is made private then memory won’t get allocated, and the object will not be created.

There are 3 types of Constructors in C++. They are as follows.

1. Default Constructor: This constructor is also known as the zero-argument constructor. This is because this constructor does not take any arguments. C++ provides us with a default constructor if we don’t create our own. The Student constructor with the print statement shown above is an example of the default constructor. This constructor (since it is called automatically if parameterized or copy constructor is not called) can be used to initialize the data members for every object i.e. it can be used to provide an initial value to the data members.

2. Parameterized Constructor: As the name suggests, this constructor accepts arguments. This can also be used to initialize the object or remove the setData() function from the classes.

Parameterized Constructor Example

#include <bits/stdc++.h>
class Student {
  
    public:
    
    string name;
    int roll_no;
    int marks;
    
    Student() {
        cout<<"Student Class Constructor called\n";
    }
    
    Student(string name,int roll_no, int marks) {
        this->name = name;
        this->roll_no = roll_no;
        this-> marks = marks;
    }
       
    void printData() {
        cout<<"My name is "<<name<<" and my roll number is "<<roll_no<<". I got "<<marks<<" marks out of 100\n";
    }
    
};

int main() {
    
    //parameterized constructor is being called
    Student s1("Guneet",2,95);
    s1.printData();
}

3. Copy Constructor: This constructor is used to initialize an object using another object of the same class. C++ provides its default copy constructor but it only performs the shallow copy. We need to deep copy the object by creating a Copy constructor of our own. An example of the same is shown below.

Copy Constructor Example

#include <bits/stdc++.h>
class Student {
  
    public:
    
    string name;
    int roll_no;
    int marks;
    
    Student() {
        cout<<"Student Class Constructor called\n";
    }
    
    Student(string name,int roll_no, int marks) {
        this->name = name;
        this->roll_no = roll_no;
        this-> marks = marks;
    }
    
    Student(Student &other) {
        this->name = other.name;
        this->roll_no = other.roll_no;
        this->marks = other.marks;
    }
    
    void setData(string name,int roll_no, int marks) {
        this->name = name;
        this->roll_no = roll_no;
        this-> marks = marks;
    }
    
    void printData() {
        cout<<"My name is "<<name<<" and my roll number is "<<roll_no<<". I got "<<marks<<" marks out of 100\n";
    }
    
};

int main() {
    
    //parameterized constructor is being called
    Student s1("Guneet",2,95);
    s1.printData();
    
  //copy constructor is being called
    Student s2(s1);
    s2.printData();
}

So, now that we have understood all about constructors, objects, and classes, let us now move to the 4 pillars of OOPS.

4 Pillars of Object-Oriented Programming (OOPS) in C++

Let us discuss the 4 pillars of OOPS in detail.

Encapsulation

Encapsulation means wrapping (or encapsulating) data and code together into a single entity (capsule). Here, data is data members and code is member functions. So, we can say that Classes in C++ help us implement encapsulation. This is because, in a Class, we have data members and member functions all wrapped into the class.

Inheritance

Inheritance is a real-life concept that we see in our daily lives. We see that the children inherit some properties (like height, build, color complexion, etc) and some behaviors (like talking, sitting/standing postures, etc) from their parents. In the same way, in OOPS in C++, a class can be a parent class (or superclass) or a child class (or subclass). So, classes can inherit data members and member functions from each other.

Let’s take the classes Car and FlyingCar, for instance. Now, in plain terms, we may deduce that a flying car is also a car that has the ability to fly. It will therefore have all the fundamental capabilities of a car as well as the added capability of flight. So, the class FlyingCar will inherit from the class Car.

The program for the above example is shown below.

Inheritance Example

#include <bits/stdc++.h>

class Car {
    
    public:
    
    string name;
    string color;
    int engineHP; //engine horse power
    
    Car() {
        
    }
    
    Car(string name, string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP; 
    }
    
    void drive() {
        cout<<name<<" Car is driving\n";
    }
    
};

class FlyingCar : public Car {
    
    public:
    FlyingCar() {
        
    }
    
    FlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void fly() {
        cout<<name<<" Car is flying\n";
    }
};

int main() {
    FlyingCar fc("SuperFly","Black",5000);
    fc.drive();
    fc.fly();
}

So, as you can see, the FlyingCar object “fc” has access to all the public data members of the Car class and also the public method drive().

Inheritance can be of multiple types. Let us discuss this in detail.

1. Single Inheritance: When one subclass inherits from one superclass, it is known as single inheritance. An example is an above Car and FlyingCar inheritance.

2. Multilevel Inheritance: As a child inherits from his father and the father inherits from his father i.e. the child’s grandfather, the real-life analogy explains the concept of multi-level inheritance. So, in multi-level inheritance, different generations extend from their upper generations. For instance, the superclass will be class Car. Now, a class called FlyingCar inherits from the class Car, and a class called HydroFlyingCar inherits from FlyingCar. The hydro-flying car is the ultimate version of a car and the advanced form of the flying car that can drive on land, fly in the air, and also navigate through water. A car is simply a car, and a flying car is merely a version of a car that can fly. This is seen below.

Multilevel Inheritance Example

#include <bits/stdc++.h>

class Car {
    
    public:
    
    string name;
    string color;
    int engineHP; //engine horse power
    
    Car() {
        
    }
    
    Car(string name, string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP; 
    }
    
    void drive() {
        cout<<name<<" Car is driving\n";
    }
    
};

class FlyingCar : public Car {
    
    public:
    FlyingCar() {
        
    }
    
    FlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void fly() {
        cout<<name<<" Car is flying\n";
    }
};

class HydroFlyingCar : public FlyingCar {
    public:
    HydroFlyingCar() {
        
    }
    
    HydroFlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void swim() {
        cout<<name<<" Car is travelling on the surface of the water\n";
    }  
};

int main() {
    HydroFlyingCar hfc("SuperHydroFly","Black",5000);
    hfc.drive();
    hfc.fly();
    hfc.swim();
}

3. Hybrid Inheritance: Think about the Car class. Then a car FlyingCar extends the Car class means that it possesses all the features of a Car as well as the capacity to fly. Let’s assume that HydroCar is a different Class that inherits from the class Car. In other words, a HydroCar has all the same capabilities as a car, plus the ability to drive on the water’s surface. In hybrid inheritance, a class can serve as a superclass for a number of other classes.

Hybrid Inheritance Example

#include <bits/stdc++.h>

class Car {
    
    public:
    
    string name;
    string color;
    int engineHP; //engine horse power
    
    Car() {
        
    }
    
    Car(string name, string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP; 
    }
    
    void drive() {
        cout<<name<<" Car is driving\n";
    }
    
};

class FlyingCar : public Car {
    
    public:
    FlyingCar() {
        
    }
    
    FlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void fly() {
        cout<<name<<" Car is flying\n";
    }
};

class HydroCar : public Car {
    public:
    HydroCar() {
        
    }
    
    HydroCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void swim() {
        cout<<name<<" Car is travelling on the surface of the water\n";
    }  
};

int main() {
    
    FlyingCar fc("SuperFly","Black",5000);
    fc.drive();
    fc.fly();
    
    HydroCar hc("SuperHydro","Black",5000);
    hc.drive();
    hc.swim();
}

4. Multiple Inheritance: A class can extend from many classes, or a subclass can have more than one superclass if there is multiple inheritance. This is seen below.

In some programming Languages like Java, multiple inheritance is not possible. However, C++ allows multiple inheritance. The question however is why programming languages like Java don’t allow multiple inheritance?

This is due to the “Deadly Diamond of Death Problem”. Let us discuss this problem in detail.

Deadly Diamond of Death Problem

Consider the following image shown below.

The diagram so demonstrates that the FlyingCar and HydroCar are both easily extensible from their superclass Car. The HydroFlyingCar, on the other hand, has two super classes with identical data members. The question of which class’s data member will the HydroFlyingCar will extend is raised in this situation. This is the multiple inheritance "deadly diamond of death" dilemma.

So, this is the problem due to which multiple inheritances is not allowed in many programming languages. However, it is allowed in C++. How does C++ overcome the “Deadly Diamond of Death Problem”? Let us see.

How to Achieve Multiple Inheritance in C++

Consider the following program.

Multiple Inheritance Example

#include <bits/stdc++.h>

class Car {
    
    public:
    
    string name;
    string color;
    int engineHP; //engine horse power
    
    Car() {
        
    }
    
    Car(string name, string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP; 
    }
    
    void drive() {
        cout<<name<<" Car is driving\n";
    }
    
};

class FlyingCar : virtual public Car {
    
    public:
    FlyingCar() {
        
    }
    
    FlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void fly() {
        cout<<name<<" Car is flying\n";
    }
};

class HydroCar : virtual public Car {
    public:
    HydroCar() {
        
    }
    
    HydroCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void swim() {
        cout<<name<<" Car is travelling on the surface of the water\n";
    }  
};

class HydroFlyingCar: public FlyingCar, public HydroCar {
    public:
    HydroFlyingCar() {
        
    }
    
    HydroFlyingCar(string name,string color, int engineHP) {
        this->name = name;
        this->color = color;
        this->engineHP = engineHP;
    }
    
    void hydroFly() {
        cout<<name<<" car is a hydro flying car. It can swim and fly both";
    }
};

int main() {
    
    FlyingCar fc("SuperFly","Black",5000);
    fc.drive();
    fc.fly();
    
    HydroCar hc("SuperHydro","Black",5000);
    hc.drive();
    hc.swim();
    
    HydroFlyingCar hfc("SuperHydroFly","Black",5000);
    hfc.drive();
    hfc.fly();
    hfc.swim();
    hfc.hydroFly();
}

As you can notice, we have used the keyword “virtual” with the superclasses FlyingCar and HydroCar. So, the use of the “virtual” keyword with both superclasses prevents the creation of multiple copies of the same data type.

So, now that we have learned completely about inheritance, let us now move to the next OOPS pillar.

Polymorphism

Poly means numerous, and morph means forms. Polymorphism, then, refers to several forms or methods of performing something. Compile-Time Polymorphism and Run-Time Polymorphism are the two types of polymorphism used in C++.

Compile Time Polymorphism

This takes place during compilation, as the name would imply. In a class, several methods with the same name may have varying numbers or kinds of parameters. This is also referred to as function overloading. Operator overloading is also a type of compile-time polymorphism. However, we will discuss it in some other article. The example below demonstrates function overloading in C++.

Function Overloading

#include <bits/stdc++.h>

int add(int a,int b) {
    return a + b;
}

int add(int a,int b, int c) {
    return a + b + c;
}


int main() {
    cout<<add(2,3)<<"\n";
    cout<<add(2,3,4)<<"\n";
}

Run-Time Polymorphism

As the name implies, this takes place in run-time. If a child class and parent class include identical methods, the run-time selection of which method to invoke is made (i.e. during object creation). Therefore, function overriding is another name for it. Below is an example of the same.

Function Overriding

#include <bits/stdc++.h>

class A {
   public:
      void meth() {
           cout<<"Class A meth invoked\n";
      }  
};

class B : public A{
    public:
        void meth() {
            cout<<"Class B meth invoked\n";
        }
};

int main() {
    A obj1;
    obj1.meth();
    
    B obj2;
    obj2.meth();
}

Now, let us discuss the last pillar of OOPS i.e. abstraction.

Abstraction

Abstraction means hiding unnecessary details from the user. In C++, abstraction can be implemented using abstract classes and access modifiers.

So, we have now discussed all 4 pillars of OOPS in C++.

We hope that you have understood all the OOPS concepts in C++. We have discussed Classes, Objects, Constructors, and all 4 pillars of OOPS in C++. We hope that you liked the discussion and have practiced all the programs once on your own. We hope to see you again soon at PrepBytes.

Leave a Reply

Your email address will not be published. Required fields are marked *