Object-Oriented Programming (OOP) is a programming paradigm that organizes programs around classes and objects. A class defines the data members and member functions, while an object is an instance of a class. OOP helps build modular, reusable, and maintainable software by modeling real-world entities.
- Promotes code reusability through inheritance.
- Improves code maintainability and scalability.
- Provides data security through encapsulation.
- Models real-world entities using classes and objects.
Characteristics of OOP
Object-Oriented Programming is characterized by several fundamental concepts that make software more modular, reusable, and easier to maintain.

Class
A class in C++ is a user-defined data type that acts as a blueprint for creating objects. It defines the data members and member functions that describe the properties and behavior of the objects.
- A class is a user-defined data type.
- It contains data members and member functions.
- Multiple objects can be created from a single class.
Example: A Car represents a class (blueprint), while BMW, Mercedes, and Audi are objects (instances) created from that class.

Object
An object in C++ is an instance of a class that represents a real-world entity. It is used to access the data members and member functions defined in the class.
- State: Represents the current values of an object's data members.
- Behavior: Represents the actions an object can perform through its member functions.
- Identity: Every object has a unique memory location that distinguishes it from other objects, even if they contain the same data.
Example: Dog is a class, while Tommy is an object (instance) of that class.

Constructor
A constructor is a special member function of a class that is automatically called when an object is created. It is mainly used to initialize the object's data members and establish its initial state.
- A constructor has the same name as the class.
- It does not have a return type, not even void.
- It is automatically invoked whenever an object of the class is created.
- It helps initialize object properties during object creation.
Example: When creating a Car object, a constructor can automatically initialize data members such as brand, model, and color.
Types of Constructors
C++ provides different types of constructors that are used to initialize objects in different ways.

- Default Constructor: A constructor that takes no parameters and initializes an object with default values.
- Parameterized Constructor: A constructor that accepts one or more parameters to initialize an object with user-defined values.
- Copy Constructor: A constructor that creates a new object by copying the state of an existing object of the same class.
- Move Constructor (C++11): A constructor that transfers the resources of a temporary object to a new object instead of copying them, improving performance.
Destructor
A Destructor is a special member function that is automatically invoked when an object is destroyed. It is primarily used to release resources such as dynamically allocated memory, open files, or network connections.
- Destructor name is the same as the class name, preceded by a tilde (~).
- A class can have only one destructor.
- It does not accept parameters and has no return type.
- It is automatically called when an object goes out of scope or is deleted.
Example: When a File object is destroyed, its destructor can automatically close the file and release associated resources.
Access Specifiers
Access specifiers control the visibility and accessibility of class members. They help implement encapsulation by restricting access to data and member functions.
- public: Members can be accessed from anywhere in the program.
- private: Members can only be accessed within the same class.
- protected: Members can be accessed within the class and its derived classes.
Example: A bank account stores its balance as a private member while allowing controlled access through public member functions such as deposit() and withdraw().
Four Pillars of OOP in C++
Object-Oriented Programming in C++ is built on four fundamental principles that help create modular, reusable, and maintainable software.
1. Abstraction
Abstraction is the process of hiding implementation details and exposing only the essential features of an object. It allows users to interact with an object without knowing how its functionality is implemented internally.
- Hides implementation details: Users access only the required functionality while the internal logic remains hidden.
- Improves maintainability: Changes to the implementation do not affect the code using the abstraction.
- Enhances flexibility: Achieved using abstract classes and pure virtual functions.
Example: An ATM or a coffee machine demonstrates abstraction, where users perform operations such as withdrawing cash or selecting a beverage without knowing the internal implementation.

How to Achieve Abstraction in C++
Abstraction in C++ is achieved using abstract classes and pure virtual functions. An abstract class defines a common interface, while derived classes provide the implementation for the abstract functions.
- Abstract Class: A class containing at least one pure virtual function. Objects of an abstract class cannot be created.
- Pure Virtual Function: A virtual function declared using = 0 that must be overridden by derived classes.
Example: An abstract class Shape can declare a pure virtual function draw(), while derived classes such as Circle and Rectangle provide their own implementations of draw(). This allows users to work with the common Shape interface without knowing the implementation details of each shape.
2. Encapsulation
Encapsulation is the process of combining data members and member functions into a single unit (class) while restricting direct access to the data. It helps protect data by allowing controlled access through member functions.
- Data members are typically hidden using the private access specifier.
- Public member functions (getters and setters) provide controlled access to the data.
- Improves data security, maintainability, and modularity.
Example: A Bank Account hides its balance using the private access specifier. The balance can only be accessed or modified through public functions such as deposit(), withdraw(), and getBalance().

3. Inheritance
Inheritance is a fundamental OOP concept in C++ that allows a class to acquire the data members and member functions of another class. It establishes an "is-a" relationship between classes and promotes code reuse.
- The class being inherited is called the base class, and the inheriting class is called the derived class.
- A derived class can access the members of the base class (subject to access specifiers) and can also define its own members.
- Promotes code reusability, extensibility, and hierarchical relationships.
Example: Dog, Cat, and Cow can be derived classes of the Animal base class because each one is an Animal.

Types of Inheritance
C++ supports the following types of inheritance:
- Single Inheritance: A derived class inherits from one base class.
- Multiple Inheritance: A derived class inherits from more than one base class.
- Multilevel Inheritance: A class is derived from another derived class, forming a chain of inheritance.
- Hierarchical Inheritance: Multiple derived classes inherit from a single base class.
- Hybrid Inheritance: A combination of two or more types of inheritance, such as multiple and multilevel inheritance.
4. Polymorphism
Polymorphism means "many forms", where the same interface can perform different actions depending on the object or context. In C++, it allows the same function or operator to exhibit different behavior in different situations.
- Allows the same interface to perform different actions.
- Achieved through function overloading, operator overloading (compile-time polymorphism), and function overriding using virtual functions (run-time polymorphism).
- Improves code flexibility, reusability, and extensibility.
Example: Different animals demonstrate polymorphism, where the same speak() function produces different outputs such as Bark, Meow, and Moo depending on whether the object is of type Dog, Cat, or Cow.

Types of Polymorphism in C++
Polymorphism in C++ is mainly classified into the following two types:

1. Compile-time Polymorphism (Static Polymorphism)
Compile-time polymorphism is resolved by the compiler during compilation. Compile-time polymorphism in C++ is achieved using:
- Function Overloading: Multiple functions have the same name but different parameter lists.
- Operator Overloading: Operators are redefined to work with user-defined types.
2. Run-time Polymorphism (Dynamic Polymorphism)
Run-time polymorphism is resolved during program execution based on the actual type of the object. Run-time polymorphism in C++ is achieved using:
- Function Overriding: A derived class provides its own implementation of a virtual function defined in the base class.
Virtual Functions
Runtime polymorphism in C++ is implemented using virtual functions. A virtual function allows a derived class to override a function of the base class, and the appropriate function is selected during program execution.
- Enables runtime polymorphism through dynamic dispatch.
- Allows derived classes to provide their own implementation of base class functions.
- Invoked using base class pointers or references.
Example: A base class Shape defines a virtual draw() function, while derived classes such as Circle and Rectangle provide their own implementations.
Relationships Between Classes in C++
Classes in C++ can be related to one another in different ways to model real-world relationships. These relationships describe how objects interact and whether one object owns another.
- Helps represent real-world relationships between classes.
- Defines how objects of different classes interact with each other.
Association
Association is a relationship between two or more classes where their objects interact with each other while remaining independent. It represents a "uses-a" relationship between objects.
- Represents a relationship between independent objects.
- Does not imply ownership between objects.
- The lifetime of one object does not depend on the other.
Example: A Teacher teaches Students, but both can exist independently.
Types of Association
Association in C++ is commonly classified into the following types.
Aggregation (Weak Association)
Aggregation represents a "has-a" relationship where one class contains or refers to another class, but both objects have independent lifetimes.
- Represents a weak ownership relationship.
- Parent and child objects can exist independently.
- Destroying the parent object does not destroy the child object.
Example: A Company has Employees, but employees can continue to exist even if the company no longer exists.

Composition (Strong Association)
Composition is a stronger form of association in which one class owns another class. The lifetime of the child object depends on the parent object.
- Represents a strong ownership relationship.
- Parent and child objects have dependent lifetimes.
- Destroying the parent object also destroys the child object.
Example: A House is composed of Rooms. If the house is destroyed, the rooms are also destroyed.

Advantages of OOP in C++
Object-Oriented Programming (OOP) offers several advantages over procedural programming by organizing programs around objects and classes.
- Code Reusability: Inheritance and classes enable existing code to be reused, reducing duplication.
- Better Organization: Programs are divided into logical classes, making the code easier to understand and maintain.
- Improved Modularity: Each class represents a separate unit, simplifying development, testing, and debugging.
- Supports the DRY Principle: Common functionality can be written once and reused across multiple classes.
- Scalability: Modular design makes it easier to extend and modify large applications.
- Data Security: Encapsulation restricts direct access to data and allows controlled access through member functions.
Limitations of OOP in C++
Although OOP provides many benefits, it also has some limitations.
- Steeper Learning Curve: Concepts such as classes, inheritance, polymorphism, abstraction, and encapsulation may be difficult for beginners.
- Higher Design Complexity: Designing effective class hierarchies and object relationships requires careful planning.
- Additional Overhead: Small programs may require extra classes and objects, making the code more complex than necessary.
- Higher Memory Usage: Objects and runtime features such as virtual functions can increase memory consumption.
- Performance Overhead: Features like dynamic binding and virtual functions may introduce a small runtime overhead compared to procedural code.