In this blog, we will be discussing all aspects of OOPs, starting with what OOPs are and how they are different from procedural programming. Moreover, we will see the basic composition of OOPs along with the practical applications of this concept in real-world scenarios.
Table of Contents:
What is the meaning of OOPs?
An Object-Oriented Programming system (OOPs) is a programming system that organizes code into reusable components called objects. Objects are the real world entities that have their own unique characteristics and behaviors. These objects could represent anything from a person with a name and address to smaller programs like widgets. OOP is particularly useful for big, complex programs or projects that need regular updates.
For example, consider you’re building a virtual world on a computer. In this world, everything is an “object” like people, animals, or things. Each object has two main characteristics: “attributes” (qualities or properties) and “behaviors” (actions or things it can do).
Want to jumpstart your career in Computer programming? Enroll in our C Programming Course and gain skills to succeed!
Difference Between Object Oriented Programming (OOPs) and Procedural Programming
The procedural programming paradigm directs the compiler on how to do a task step-by-step. It treats the functions and the data as two separate entities. On the other hand, OOPs bind the data and methods together. These two programming approaches differ from each other in several ways. The following table highlights the major differences between them.
Procedural Programming | Object Oriented Programming |
This programming system follows a top-down approach. | In object-oriented programming, a bottom-up approach is followed. |
Programs consist of a collection of instructions telling the compiler what to do step-by-step, which makes the large codes difficult to maintain. | Instead of a set of instructions, objects are created that combine both data and methods. So the code is easier to maintain. |
The programs are divided into small parts called functions. | Here, a program is divided into small parts called objects. |
In procedural programming, functions are considered the first aspect and data the second. | In OOPs, the main focus is on accessing data, making it the main aspect. |
Programs are not secure as there is no data hiding. | It provides more security as the concept of encapsulation is present in OOPs. |
Adding new functions or data is not simple. | It is easy to add more data or functions to OOPs. |
This programming system is not based on the real world. | It is based on the real world and contains real-world entities called objects. |
Code reusability is not possible. | Code reusability is possible. |
It is for short-length projects and programs. | It can be used for large and complex programs. |
PASCAL, C , BASIC, and COBOL are some of the procedural programming languages. | C++, Java, C#, and Python are OOP languages. |
Check out our blog on What is Friend Function in C++? to learn more about C++ and its functions.
Why are OOPs needed?
The major reason why we need OOPs is code reusability, which means the ability to use the same code again and again in the program. It saves a lot of time, as we do not need to create new functions for every similar situation. This facility was not present in the procedural programming paradigm. It is a better programming style than functional programming, as it also provides code security by using functionalities like data abstraction and encapsulation.
Check out C++ Interview Questions and answers to ace your next C++ interview.
Key Concepts of OOPs in C++ with Examples
There are six major components of object-oriented programming. All of these components provide different functionalities. The list of these concepts is given below:
- Classes
- Objects
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
Apart from these six basic pillars of OOPs, there are two more important concepts in this programming system, i.e., message passing and dynamic binding. We will discuss all these components in detail in the section given below:
1. Classes
To create an object, we first need to create a class. It is like a container that has the data members and member functions. Once a class is created, we can create any number of objects that belong to that class. It is basically a collection of similar types of objects; for example, if we create a class vehicle, then “car”, “bike”, and “scooter” can be the objects of this class.
It is important to note that class doesn’t occupy any memory. The memory is associated with instances (objects) of the class rather than the class itself.
To create a class in C++ the syntax is as follows:
class NameofClass{
Access specifier: // public, private, or protected
Data members; // variables
Member functions; // functions to access the data members
};
2. Objects
Objects are like user-defined data types, which means we can control how they function in a program. Objects are connected to each other through these member functions. Access to the data members of an object is restricted to the functions of that object.
Objects relate to real-world entities that have an identity, state, and behavior. Identity is the name that we use to refer to that object. The state of an object refers to the information that is related to it, and the behavior represents the action of the object that can modify its state. For example, a person has an identity (name), state ( age, weight, height), and behavior (speaking, walking, eating).
The syntax for creating an object is:
ClassName NameOfObject;
For accessing data members and member functions, we need to follow the syntax given below:
Objectname.MemberFunctionname();
Now we will create a simple class with an object that will access the data members.
#include <iostream>
using namespace std;
class Test{
// Access specifier
public:
// Data Member
int num;
// Member Function()
void printnumber(){
cout << "The number is:" << num; }
};
int main()
{
// Declare an object of class Test
Test object1;
// accessing data member
object1.num = 1000;
// accessing member function
object1.printnumber();
return 0;
}
The output of this program is:
The number is:1000
Get 100% Hike!
Master Most in Demand Skills Now!
3. Encapsulation
In C++, encapsulation means binding together the related data and functions within a single unit called a class. This organizes the code and also protects the encapsulated data from direct manipulation from outside the class. This is also called data or information hiding. It enhances code security and maintainability.
To understand this with an analogy, consider a capsule. It encapsulates medicine inside it, and the outer cover protects the medicine from external conditions. Similar to this encapsulation is the method that is used to protect the data members and member functions from being directly accessed.
We can modify the access to a class. There are three types of access modifiers in C++, and those are:
- Public: The members declared as public are accessible from outside the class.
- Private: The private members of a class are not accessible from outside the class. These can only be accessed within the class itself.
- Protected: The protected members are similar to private members but have limited accessibility to derived classes. Protected members are accessible within the class and its derived classes.
If you do not mention any access specifierS while creating the class, then the class will be private by default. Let’s understand the concept of encapsulation and access modifiers with the help of a simple example:
#include <iostream>
using namespace std;
class AccessExample {
public:
// Public member variable
int publicVar;
// Public member function
void publicFunction() {
cout << "Public Function" << endl;
}
private:
// Private member variable
int privateVar;
// Private member function
void privateFunction() {
cout << "Private Function" << endl;
}
protected:
// Protected member variable
int protectedVar;
// Protected member function
void protectedFunction() {
cout << "Protected Function" << endl;
}
public:
// Public function accessing private and protected members
void accessMembers() {
// Accessing public member
cout << "Public Variable: " << publicVar << endl;
publicFunction();
// Accessing private member (within the class)
cout << "Private Variable: " << privateVar << endl;
privateFunction();
// Accessing protected member (within the class)
cout << "Protected Variable: " << protectedVar << endl;
protectedFunction();
}
};
int main() {
AccessExample obj;
// Accessing public members
obj.publicVar = 42;
obj.publicFunction();
// Accessing protected members (not directly, but through a public function)
obj.accessMembers();
// as privateVar and privateFunction are not directly accessible outside the class.
// obj.privateVar = 10;
// obj.privateFunction();
return 0;
}
In this example, the class “AccessExample” has members under all three access specifiers: “public”, “private”, and “protected”. Inside the “main” function we are accessing the public members directly, which indirectly accesses private and protected members through another public function (accessMembers).
Trying to access private members directly from the “main” function would result in a compilation error since private members are not directly accessible outside the class.
This program will give the following output:
Public Function
Public Variable: 42
Public Function
Private Variable: 0 // Note: Default-initialized to 0, privateVar is not directly accessible.
Private Function
Protected Variable: 0 // Note: Default-initialized to 0, protectedVar is not directly accessible.
Protected Function
Check out this blog to learn how is Python different from C++.
4. Abstraction
The concept of abstraction is closely related to encapsulation. Abstraction simplifies complex systems by hiding unnecessary details. It’s like using a map to navigate a city. The map doesn’t show every building, street sign, or tree, but it provides essential information about the city’s layout, allowing you to get around without getting lost.
Example of abstraction:
#include <iostream>
using namespace std;
class AbstractionExample {
private:
int a, b; // Corrected variable names
public:
// Method to set values of data members
void setvalues(int x, int y) {
a = x;
b = y;
}
void display() {
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
};
int main() {
AbstractionExample obj; // Corrected class name
obj.setvalues(20, 40); // Corrected method name
obj.display();
return 0;
}
In this example, we have created a class, AbstractionExample. The class encapsulates two private data members, a and b, representing internal data that is hidden from external access. The class provides two public methods: setvalues() and display(). The setvalues() method allows external code to set the values of a and b. Inside the main() function, an object of the class is created, and the values of a and b are set to 20 and 40. The display() method is then used to print the values of a and b on the screen.
The output of this example will be:
a = 20
b = 40
5. Inheritance
Using this feature of OOP, a new class, known as the “derived class” or “child class,” can inherit properties and characteristics from an existing class called the “base class” or “parent class.” This process allows the derived class to inherit all the features of the base class without changing its properties.
The derived class can then extend its functionality by adding new features unique to itself without impacting the base class. Basically, the derived class is the extended version of the base class, maintaining the existing properties while introducing its own distinct attributes. Inheritance promotes code reusability and the creation of a hierarchy of classes with shared characteristics. There are five different types of inheritance in C++, which are listed below:
- Single Inheritance.
- Multiple Inheritance.
- Multilevel Inheritance.
- Hierarchical Inheritance.
- Hybrid Inheritance.
Let’s understand inheritance with the help of the following example:
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
cout << "Animal is eating." << endl;
}
void sleep() {
cout << "Animal is sleeping." << endl;
}
};
// Derived class (inherits from Animal)
class Dog : public Animal {
public:
void bark() {
cout << "Dog is barking." << endl;
}
};
int main() {
// Create an object of the derived class
Dog myDog;
// Inherited methods from the base class
myDog.eat();
myDog.sleep();
// New method in the derived class
myDog.bark();
return 0;
}
This code will give the following output:
Animal is eating.
Animal is sleeping.
Dog is barking.
Here we have a base class Animal that contains animal behaviors such as eating and sleeping. A derived class, Dog, is inheriting from the Animal class using the public access specifier. In the main() function, an object of the Dog class, myDog, is instantiated. Through inheritance, myDog gains access to the inherited methods, enabling it to exhibit generic animal behavior. Additionally, the Dog class introduces a new method, bark, which is specific to dogs.
Explore these top OOPs Interview Questions and ace your next interview to get your dream job!
6. Polymorphism
Polymorphism literally means “having many forms,”. It is the capability of a message or operation to be utilized in many ways. In other words, it is the ability of an object to have multiple characteristics or behaviors. Much like how a person can simultaneously play the roles of a father, a husband, and an employee, demonstrating different behaviors in different situations, this is known as polymorphism.
In programming, polymorphism is expressed through operations that can behave differently based on the types of data involved. C++ facilitates polymorphism through features like compile-time polymorphism and run-time polymorphism.
Compile-time polymorphism: This type of polymorphism is obtained through operator overloading or function overloading.
Run-time polymorphism: Run-time polymorphism is achieved through function overriding.
To understand the concept of polymorphism, see the following example:
#include <iostream>
// Function to multiply two integers
int multiplyNumbers(int a, int b) {
return a * b;
}
// Overloaded function to multiply three integers
int multiplyNumbers(int a, int b, int c) {
return a * b * c;
}
int main() {
// Example of using the overloaded functions
int product1 = multiplyNumbers(5, 7);
int product2 = multiplyNumbers(3, 8, 2);
std::cout << "Product of two numbers: " << product1 << std::endl;
std::cout << "Product of three numbers: " << product2 << std::endl;
return 0;
}
In this example:
This example shows polymorphism. Here we are using the function multiplyNumbers() twice in the program, but with a different number of arguments. We are modifying this function based on our needs. First, we are multiplying two numbers and then three numbers.
This will give the following output:
Product of two numbers: 35
Product of three numbers: 48
7. Message Passing
Ever wondered how objects communicate with each other? Well, they communicate by passing information to each other, which is similar to messaging. A message is a request for the implementation of a function. The object that receives the message invokes the function to generate the desired output. The process involves stating the name of the object, the name of the function, and the message (information to be sent).
8. Dynamic Binding
It is the process of linking together the function call and the code to be executed in response to that call. Dynamic binding means that the code that is going to be executed in response to the function call is decided at run-time, unlike static binding, where it is decided during build-time. This can be understood with the help of the following example:
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() {
cout << "Drawing a generic shape" << endl;
}
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing a rectangle" << endl;
}
};
int main() {
Shape* myShape;
Circle myCircle;
Rectangle myRectangle;
myShape = &myCircle;
myShape->draw(); // Dynamic binding - Circle's draw is called
myShape = &myRectangle;
myShape->draw(); // Dynamic binding - Rectangle's draw is called
return 0;
}
In this example, the base class Shape has a virtual function draw(). Two derived classes, Circle and Rectangle, override this function. The main() function uses a pointer of type Shape to point to objects of both the Circle and Rectangle classes, which represents dynamic binding. The appropriate draw() method is called based on the actual object being pointed to.
This program will give the following output:
Drawing a circle
Drawing a rectangle
Practical Applications of OOPs in C++
There are many real-life systems where OOP has been used. These systems are very complex and difficult to build. But OOP has made this task easier. Given below are some examples where OOP is used.
- In GUI (Graphical User Interface) design is like Windows. Many Windows systems have been developed using OOP methods.
- In object-oriented databases
- In embedded systems like medical devices and home appliances.
- In the browser’s components, such as the rendering engine, network stack, and JavaScript interpreter.
- In structuring operating systems
- In game development
Key-Takeaways
The concept of OOPs helps in organization, security, and reusability of the code. The main OOPs concepts include classes, objects, encapsulation, abstraction, inheritance, polymorphism, message passing, and dynamic binding. It is beneficial in designing and developing complex systems such as GUIs, databases, embedded systems, and more. All these functionalities make OOPs a very useful concept.