Introduction of Object Oriented
Programming
Object-Oriented Programming or OOPs refers to languages that use objects in programming.
Object-oriented programming aims to implement real-world entities like inheritance, hiding,
polymorphism, etc in programming. The main aim of OOP is to bind together the data and the
functions that operate on them so that no other part of the code can access this data except that
function.
Programming languages designed primarily for OOP include:
Java
Python
C++
What are the benefits of OOP?
Benefits of OOP include:
Modularity. Encapsulation enables objects to be self-contained, making troubleshooting and
collaborative development easier.
Reusability. Code can be reused through inheritance, meaning a team does not have to write the
same code multiple times.
Productivity. Programmers can construct new programs quicker through the use of multiple
libraries and reusable code.
Easily upgradable and scalable. Programmers can implement system functionalities
independently.
Interface descriptions. Descriptions of external systems are simple, due to message passing
techniques that are used for objects communication.
Security. Using encapsulation and abstraction, complex code is hidden, software maintenance is
easier and internet protocols are protected.
Flexibility. Polymorphism enables a single function to adapt to the class it is placed in. Different
objects can also pass through the same interface.
Why do we need object-oriented programming?
To make the development and maintenance of projects more effortless.
To provide the feature of data hiding that is good for security concerns.
We can solve real-world problems if we are using object-oriented programming.
It ensures code reusability.
It lets us write generic code: which will work with a range of data, so we don't have to
write basic stuff over and over again.
Data Members Explained
Variables defined within a class are referred to as data members.
Access to a class's private data is restricted and can only be achieved through its member
functions.
Data members are versatile and can be any data type, whether built-in or custom-defined by the
user.
Member Functions Explained
Functions defined within a class are referred to as member functions.
These functions interact directly with the class's data members, retrieving and manipulating their
values.
You can define member functions either inside the class declaration or separately outside it.
Member functions have the privilege to access both the public and private components of the
class.
How to Define Member Functions
Member functions have two possible locations for their definitions:
Directly within the class declaration.
Separately, outside the class body.
Defining Member Functions within a Class
Format: (Placed inside the class declaration)
Return_type function name (parameter_list) {
// function implementation
}
Accessing data members and member functions:
The data members and member functions of the class can be accessed using the dot („.‟)
operator with the object. For example, if the name of the object is obj and you want to access
the member function with the name printName () then you will have to write [Link]
().
Defining Member Functions outside Class
Functions declared in a class must be defined outside it.
Definitions resemble normal functions with a header and body.
Member functions include a class label in the header to identify their class to the compiler.
How to Define Member Functions inside a Class
Structure: (Declared within the class body)
Return_type functionname(parameter_list) {// code defining the function's behavior}
Writing Member Functions outside the Class Definition
The typical structure looks like this:
return_type ClassName::FunctionName(parameter_list) {// implementation details}
The double colon (::), known as the scope resolution operator, links the function explicitly to its
class.
Defining functions this way keeps the class declaration clean and improves the overall
organization and clarity of your code.
OOPs Concepts:
Class
Objects
Data Abstraction
Encapsulation
Inheritance
Polymorphism
Dynamic Binding
Message Passing
1. Class:
A class is a user-defined data type. It consists of data members and member functions, which
can be accessed and used by creating an instance of that class. It represents the set of properties
or methods that are common to all objects of one type. A class is like a blueprint for an
object.
For Example: Consider the Class of Cars. There may be many cars with different names and
brands but all of them will share some common properties like all of them will have 4 wheels,
Speed Limit, Mileage range, etc. So here, Car is the class, and wheels, speed limits, mileage
are their properties.
2. Object:
It is a basic unit of Object-Oriented Programming and represents the real-life entities. An
Object is an instance of a Class. When a class is defined, no memory is allocated but when it is
instantiated (i.e. an object is created) memory is allocated. An object has an identity, state, and
behavior. Each object contains data and code to manipulate the data. Objects can interact
without having to know details of each other‟s data or code, it is sufficient to know the type of
message accepted and type of response returned by the objects.
For example “Dog” is a real-life Object, which has some characteristics like color, Breed,
Bark, Sleep, and Eats.
3. Data Abstraction:
Data abstraction is one of the most essential and important features of object-oriented
programming. Data abstraction refers to providing only essential information about the data to
the outside world, hiding the background details or implementation. Consider a real-life
example of a man driving a car. The man only knows that pressing the accelerators will
increase the speed of the car or applying brakes will stop the car, but he does not know about
how on pressing the accelerator the speed is increasing, he does not know about the inner
mechanism of the car or the implementation of the accelerator, brakes, etc in the car. This is
what abstraction is.
4. Encapsulation:
Encapsulation is defined as the wrapping up of data under a single unit. It is the mechanism
that binds together code and the data it manipulates. In Encapsulation, the variables or data of a
class are hidden from any other class and can be accessed only through any member function
of their class in which they are declared. As in encapsulation, the data in a class is hidden from
other classes, so it is also known as data-hiding.
Consider a real-life example of encapsulation, in a company, there are different sections like
the accounts section, finance section, sales section, etc. The finance section handles all the
financial transactions and keeps records of all the data related to finance. Similarly, the sales
section handles all the sales-related activities and keeps records of all the sales. Now there may
arise a situation when for some reason an official from the finance section needs all the data
about sales in a particular month. In this case, he is not allowed to directly access the data of
the sales section. He will first have to contact some other officer in the sales section and then
request him to give the particular data. This is what encapsulation is. Here the data of the sales
section and the employees that can manipulate them are wrapped under a single name “sales
section”.
5. Inheritance:
Inheritance is an important pillar of OOP (Object-Oriented Programming). The capability of a
class to derive properties and characteristics from another class is called Inheritance. When we
write a class, we inherit properties from other classes. So when we create a class, we do not
need to write all the properties and functions again and again, as these can be inherited from
another class that possesses it. Inheritance allows the user to reuse the code whenever possible
and reduce its redundancy.
The inheritance can be classified on the basis of the relationship between the derived class and
the base class. In C++, we have 5 types of inheritances:
Single Inheritance
Multilevel Inheritance
Multiple Inheritance
Hierarchical Inheritance
Hybrid Inheritance
6. Polymorphism:
The word polymorphism means having many forms. In simple words, we can define
polymorphism as the ability of a message to be displayed in more than one form. For example,
A person at the same time can have different characteristics. Like a man at the same time is a
father, a husband, an employee. So the same person posses different behavior in different
situations. This is called polymorphism.
Types of Polymorphism:
1. Compile-Time Polymorphism
Also known as early binding and static polymorphism. Compile-time Polymorphism refers to
the mechanism in C++ where the compiler determines which function to call during compilation
based on the function's signature and the context in which it is invoked. This is typically
achieved through function overloading and operator overloading.
A. Function Overloading
Function overloading is a feature of object-oriented programming where two or more functions
can have the same name but behave differently for different parameters. Such functions are said
to be overloaded; hence, this is known as Function Overloading. Functions can be overloaded
either by changing the number of arguments or changing the type of arguments.
Rules of Function Overloading in C++
Different parameters or three different conditions:
1. These functions have different parameter type
sum(int a, int b)
sum(double a, double b)
2. These functions have a different number of parameters
sum(int a, int b)
sum(int a, int b, int c)
3. These functions have a different sequence of parameters
sum(int a, double b)
sum(double a, int b)
Explanation: In the above example, two add() functions are defined with the same name but
different parameter types: one for integers and one for floating-point numbers. The correct
version of the add() function is called at compile time based on the type of arguments passed,
allowing the same function name to be used for different data types.
B. Operator Overloading
C++ has the ability to provide the operators with a special meaning for particular data type, this
ability is known as operator overloading. For example, we can make use of the addition
operator (+) for string to concatenate two strings and for integer to add two integers.
The << and >> operator are binary shift operators but are also used with input and output
streams. This is possible due to operator overloading.
2. Runtime Polymorphism
Runtime Polymorphism in C++, also known as late binding or dynamic Polymorphism, is
achieved through function overriding, virtual function.
Unlike compile-time Polymorphism, where the function call is resolved at compile time, run
time Polymorphism in C++ resolves the function call at runtime.
This allows for greater flexibility as the specific function implementation is determined based on
the actual object type during program execution.
Function Overriding
Function Overriding occurs when a derived class defines one or more member functions of the
base class. That base function is said to be overridden. The base class function must be declared
as virtual function for runtime polymorphism to happen.
A function is a block of code that performs a specific task. It takes input, processes it, and returns
an output. Function Overriding in C++ is a type of polymorphism where a derived class
redefines a function from its base class using the same name, return type, and parameters (i.e.,
the same function signature).
Conditions:
The base class function must be virtual.
The derived class must use the same signature.
It's a form of runtime polymorphism (dynamic binding).
How Does It Work?
If you call the function using a base class object, the base class version is executed.
If you call it using a derived class object, the derived class version is executed.
7. Dynamic Binding:
In dynamic binding, the code to be executed in response to the function call is decided at
runtime. Dynamic binding means that the code associated with a given procedure call is not
known until the time of the call at run time. Dynamic Method Binding One of the main
advantages of inheritance is that some derived class D has all the members of its base class B.
Once D is not hiding any of the public members of B, then an object of D can represent B in
any context where a B could be used. This feature is known as subtype polymorphism.
8. Message Passing:
It is a form of communication used in object-oriented programming as well as parallel
programming. Objects communicate with one another by sending and receiving information to
each other. A message for an object is a request for execution of a procedure and therefore will
invoke a function in the receiving object that generates the desired results. Message passing
involves specifying the name of the object, the name of the function, and the information to be
sent.
Function Overloading Function Overriding
Function Overloading provides multiple definitions of Function Overriding is the redefinition of base class
the function by changing signature. function in its derived class with same signature.
An example of compile time polymorphism. An example of run time polymorphism.
Function signatures should be different. Function signatures should be the same.
Overloaded functions are in same scope. Overridden functions are in different scopes.
Overloading is used when the same function has to
Overriding is needed when derived class function has
behave differently depending upon parameters passed to
to do some different job than the base class function.
them.
A function has the ability to load multiple times. A function can be overridden only a single time.
In function overloading, we don't need inheritance. In function overriding, we need an inheritance.
Functions in C++
A function is a reusable block of code that performs a specific task. It divides a program into
smaller logical units, improves readability, and makes code easier to maintain. A function can
accept parameters, execute statements, and optionally return a value.
A function Allows you to write a piece of logic once and reuse it wherever needed in the
program.
This helps keep your code clean, organized, easier to understand and manage.
Function Syntax
To work with functions in C++, it is important to understand how they are written, declared, and
called. This section covers function syntax, declaration vs definition, and how to call a function
in a program.
Function Syntax in C++
A function in C++ follows this general format:
Basic structure of a C++ function.
Each part has a specific role:
Return type: Specifies what type of value the function returns. Use void if there is no return
value.
Function name: The name you will use to call the function.
Parameter list: Inputs that the function accepts. It can be empty if no inputs are needed.
Function body: The block of code that runs when the function is called.
Function Declaration vs Definition
A function declaration introduces a function to the compiler by specifying its return type, name,
and parameters without the body, and is used when the function is defined later or in another file.
// Declaration
int add(int, int);
Function definition contains the actual code that specifies what the function does when it is
called.
//Definition
int add(int a, int b) {
return a + b;
}
Declaration Needed in C++
A function must be declared before it is used so the compiler knows its name, return type,
and parameters even if its definition appears later or in another file.
This allows the compiler to correctly recognize and validate function calls in larger or multi-
file programs.
Calling a Function
A function is used by calling its name followed by parentheses, passing required arguments if
any, which executes the code inside the function.
Parameters or Arguments
A parameter is a variable written in a function definition that receives a value when the function
is called. An argument is the actual value passed to a function during the function call.
Syntax:
return_type name(type1 name1, type2 name2...)
{Function bodyreturn val;}
void add(int a, int b) // a and b are parameters
Explanation:
printNum() is defined with one integer parameter n, so it can accept and print only one
integer value at a time.
The function is called twice, once with num1 and once with num2, and prints each value
separately.
Inside the function, the passed value is accessed using the parameter name n, not num1 or
num2, due to variable scope.
We cannot pass both numbers in a single call because the function is defined to accept only
one parameter.
What is Constructor?
Constructors are special methods that are automatically called whenever an object of a class is
created. A constructor is different from normal functions in following ways:
A constructor has same name as the class itself
Don't have return type
Automatically called when an object is created.
If we do not specify a constructor, C++ compiler generates a default constructor for us
(expects no parameters and has an empty body).
Types of Constructors in C++
Constructors can be classified based on the situations they are being used in. There are 3 types of
constructors in C++:
1. Default Constructor
2. Parameterized Constructor
3. Copy Constructor
1. Default Constructor
A default constructor is automatically created by the compiler if no constructor is defined. It
takes no arguments and initializes members with default values, and it is not generated if the
programmer defines any constructor.
Explanation: The class A does not contain any explicitly defined constructor, so its object is
created without passing any parameters. In this case, the compiler automatically provides and
uses the default constructor.
2. Parameterized Constructor
A parameterized constructor lets us pass arguments to initialize an object's members. It is created
by adding parameters to the constructor and using them to set the values of the data members.
Explanation: The parameterized constructor is called when we create object a with integer
argument 10 . As defined, it initializes the member variable val with the value 10.
3. Copy Constructor
A copy constructor is a special type of constructor used to create a new object using an existing
object of the same class.
Compiler creates a default copy constructor if there is no user defined constructor. This
compiler created constructor does a shallow copy and works well for basic types, but does
not work for dynamic allocated memory.
If a class has pointers or runtime resources (like dynamic memory, file handles, network
connections), a custom copy constructor is needed. Otherwise, deletion of one object might
cause deletion of an unrelated object member.
Explanation: The copy constructor is used to create a new object a2 as a copy of the object a1. It
is called automatically when the object of class A is passed as constructor argument.
Just like the default constructor, the C++ compiler also provides an implicit copy
constructor if the explicit copy constructor definition is not present.
Default Copy Constructor:
When a copy constructor is not defined, the C++ compiler automatically supplies with its self-
generated constructor that copies the values of the object to the new object.
User Defined Copy Constructor
C++ also allows programmers to create their own version of copy constructor known as user
defined or explicit copy constructor.
Class name (const class name & obj) {
//body of copy constructor
}
Here, the const is optional but is added so that we do not modify the obj by mistake. Copy
constructor takes a reference to an object of the same class as an argument.
When is the Copy Constructor Called?
In C++, a copy constructor may be called in the following cases:
When an object of the class is returned by value.
When an object of the class is passed (to a function) by value as an argument.
When an object is constructed based on another object of the same class.
When the compiler generates a temporary object.
It is, however, not guaranteed that a copy constructor will be called in all these cases, because
the C++ Standard allows the compiler to optimize the copy away in certain cases, one example
is the return value optimization (sometimes referred to as RVO).
Destructors in C++
A destructor is a special member function, prefixed with '~', that is automatically called when
an object goes out of scope or is destroyed to free resources like memory, files, or connections.
Destructor neither requires any argument nor returns any value.
A destructor cannot be declared as static or const.
A class can have only one destructor, and it cannot be overloaded.
Destructors release resources and destroy objects in reverse order of creation.
Syntax
Destructors are automatically present in every C++ class but we can also redefine them using
the following syntax.
~className(){
// Body of destructor
}
where, tilda(~) is used to create destructor of a className.
Types of Destructors in C++
Destructor is a special type of member function that every class must have. The following are
types of destructors in C++:
Default destructor: C++ offers a default destructor which is invoked if there is no destructor
explicitly defined. The default constructor deallocates memory taken up by all the data
members of the object.
Static Destructor: A static destructor is the destructor which is used to deallocates memory
occupied by statically created objects.
Dynamic Destructor: A dynamic destructor is the destructor which is used to deallocate
memory occupied by objects created dynamically using the new operator. It is triggered when
the delete operator is used.
A default destructor is required because a destructor is essential to destroying an object. So, if
there is no explicitly defined destructor then there should be something else that deallocates
memory taken up by the object.
The default destructor like the explicitly defined destructor cannot take any parameters. It
simply deallocates memory occupied by the object and does nothing else.
The default destructor is called automatically when an object goes out of scope. Its objective is
to deallocate memory used by the object statically or at run time.
Syntax of Default Destructor:
~ClassName();
No return type (not even void)
No parameters
Automatically invoked
When do we need to write a user-defined destructor?
If we don‟t write a destructor, the compiler provides a default one.
The default destructor works fine for classes without dynamic memory or pointers.
If a class has pointers or dynamically allocated memory, we must write a destructor.
A user-defined destructor releases memory or other resources before the object is
destroyed.
Writing a destructor in such cases prevents memory leaks.
Note: When the object is destroyed, the destructor releases the dynamically allocated
resources, which in this case is the pointer.
When is the destructor called?
1. When the function ends.
2. When the program ends.
3. When a block containing local variables ends.
4. When a delete operator is called.
Program to demonstrates the number of times constructors and destructors are called.
How to call destructors explicitly?
Destructor can also be called explicitly for an object. We can call the destructors explicitly
using the following statement:
object_name.~class_name()
How Constructor and Destructor are called when the object is Created and Destroyed
As constructor is the first function called by the compiler when an object is created and the
destructor is the last class member called by the compiler for an object. If the constructor and
destructor are not declared by the user, the compiler defines the default constructor and
destructor of a class object.
Let‟s see a code to get the proper idea of how constructor and destructor are called:
First, we will create a class with single parametrized constructors and a destructor. Both of them
contain print statements to give an idea of when they are called.
Inheritance in C++
The process by which one class objects derive the properties of other classes or classes while
maintaining its own is called Inheritance.
The parent class from which other classes are derived is called a super class or base class,
whereas the child classes that are generated out of the base classes are called the derived classes
or subclasses. In this, the derived classes can have their own methods and properties while
maintaining the inherited properties of their parent classes. These added properties are confined
to these subclasses only and do not manipulate the parent class. In this way, the derived classes
have the properties of both, i.e., itself and the parent classes.
Example: In the following example, Animal is the base class and Dog, Cat and Cow are
derived classes that extend the Animal class.
Syntax:
class ChildClass : public ParentClass
{
// Additional fields and methods
};
How Inheritance Works in C++?
The colon (:) with an access specifier is used for inheritance in C++. It allows the derived class
(child class) to inherit the data members (fields) and member functions (methods) of the base
class (parent class).
When a class inherits another class, it gets all the accessible members of the parent class, and the
child class can also redefine (override) or add new functionality to them.
Protected Specifier
The protected specifier makes members accessible inside the class itself and in
its derived (child) classes, but not form outside code.
It is mainly used in inheritance, allowing child classes to reuse or modify data and functions
while still keeping them hidden from the outside world.
Types of Inheritance in C++:
1. Single Inheritance
In single inheritance, a sub-class is derived from only one super class. It inherits the properties
and behavior of a single-parent class. Sometimes, it is also known as simple inheritance.
Syntax for Single Inheritance:
class Base {
//class members
};
class Derive : <access_specifier> Base {
//class members
};
2. Multiple Inheritance
Multiple Inheritance is a feature of C++ where a class can inherit from more than one base class.
It allows a derived class to combine properties and behavior from multiple parent classes,
making code more reusable and flexible.
A class can be derived from more than one base class. For example:
A CHILD class is derived from the FATHER and MOTHER class
A PETROL class is derived from the LIQUID and FUEL class.
Syntax:
class Base1 {
// Base class 1 members
};
class Base2 {
// Base class 2 members
};
class Derived : public Base1, public Base2 {
// Derived class members
};
3. Multilevel Inheritance
Multilevel inheritance in C++ means a class is derived from another derived class, forming a
chain of inheritance.
Syntax:
class baseClass {
//Here's a base class members
};
class derivedClass1 : public baseClass {
// Members of derivedClass1
};
class derivedClass2 : public derivedClass1 {
// Members of derivedClass2
};
4. Hierarchical Inheritance
In hierarchical inheritance, more than one subclass is inherited from a single base class. i.e. more
than one derived class is created from a single base class. For example, cars and buses both are
vehicle.
Syntax of Hierarchical Inheritance:
class base_class {
... .. ...
}
class first_derived_class: public base_class {
... .. ...
}
class second_derived_class: public base_class {
... .. ...
}
class third_derived_class: public base_class {
... .. ...
}
5. Hybrid Inheritance
Hybrid inheritance is a complex form of inheritance in object-oriented programming (OOP). In
Hybrid Inheritance, multiple types of inheritance are combined within a single class hierarchy,
enabling a varied and flexible structure of classes.
In hybrid inheritance, within the same class, we can have elements of single inheritance,
multiple inheritance, multilevel inheritance, and hierarchical inheritance.
The major goal of hybrid inheritance is to enhance code reusability by making it simpler for
programmers to use the methods and attributes that are already present in other classes.
Hybrid inheritance has several advantages over other inheritances as it increases the reusability
of software elements, enables quicker code development lowers coding errors by avoiding code
duplication across classes, and establishes a more clearly defined relationship between classes in
object-oriented programming. It also provides a structured way to organize classes with shared
attributes and behaviors.