Skip to Content
ClassesOOPs Concepts

OOPs Concepts in C++

Object-Oriented Programming (OOP) is a programming paradigm based on the concept of “objects” which contain data and code. C++ supports four fundamental OOP principles.

The Four Pillars of OOP

  1. Encapsulation - Bundling data and methods together
  2. Abstraction - Hiding complex implementation details
  3. Inheritance - Creating new classes from existing ones
  4. Polymorphism - Using a single interface for different data types

1. Encapsulation

Encapsulation is the bundling of data and methods that operate on that data within a single unit (class), and restricting direct access to some components.

Benefits:

  • Data hiding and security
  • Flexibility and maintainability
  • Control over data

Example:

#include <iostream> #include <string> using namespace std; class Employee { private: string name; double salary; public: // Setter methods void setName(string n) { name = n; } void setSalary(double s) { if (s >= 0) { // Validation salary = s; } } // Getter methods string getName() { return name; } double getSalary() { return salary; } }; int main() { Employee emp; emp.setName("John"); emp.setSalary(50000); cout << "Employee: " << emp.getName() << endl; cout << "Salary: $" << emp.getSalary() << endl; return 0; }

Output:

Employee: John Salary: $50000

2. Abstraction

Abstraction means hiding complex implementation details and showing only essential features of an object.

Benefits:

  • Reduces complexity
  • Enhances code reusability
  • Improves maintainability

Example using Abstract Class:

#include <iostream> using namespace std; // Abstract class class Shape { public: // Pure virtual function (abstract method) virtual double getArea() = 0; virtual void display() = 0; }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double getArea() override { return 3.14159 * radius * radius; } void display() override { cout << "Circle with radius: " << radius << endl; cout << "Area: " << getArea() << endl; } }; class Rectangle : public Shape { private: double length, width; public: Rectangle(double l, double w) : length(l), width(w) {} double getArea() override { return length * width; } void display() override { cout << "Rectangle " << length << "x" << width << endl; cout << "Area: " << getArea() << endl; } }; int main() { Circle circle(5); Rectangle rect(4, 6); circle.display(); cout << endl; rect.display(); return 0; }

Output:

Circle with radius: 5 Area: 78.5398 Rectangle 4x6 Area: 24

3. Inheritance

Inheritance allows a class to inherit properties and methods from another class.

Types of Inheritance:

  • Single Inheritance
  • Multiple Inheritance
  • Multilevel Inheritance
  • Hierarchical Inheritance
  • Hybrid Inheritance

Example:

#include <iostream> #include <string> using namespace std; // Base class class Animal { protected: string name; public: Animal(string n) : name(n) {} void eat() { cout << name << " is eating." << endl; } void sleep() { cout << name << " is sleeping." << endl; } }; // Derived class class Dog : public Animal { public: Dog(string n) : Animal(n) {} void bark() { cout << name << " is barking: Woof! Woof!" << endl; } }; // Another derived class class Cat : public Animal { public: Cat(string n) : Animal(n) {} void meow() { cout << name << " is meowing: Meow! Meow!" << endl; } }; int main() { Dog dog("Buddy"); dog.eat(); dog.bark(); cout << endl; Cat cat("Whiskers"); cat.sleep(); cat.meow(); return 0; }

Output:

Buddy is eating. Buddy is barking: Woof! Woof! Whiskers is sleeping. Whiskers is meowing: Meow! Meow!

Learn more about Inheritance in detail.

4. Polymorphism

Polymorphism means “many forms”. It allows objects of different classes to be treated as objects of a common base class.

Types:

  1. Compile-time Polymorphism (Function Overloading, Operator Overloading)
  2. Runtime Polymorphism (Virtual Functions)

Function Overloading Example:

#include <iostream> using namespace std; class Calculator { public: int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } int add(int a, int b, int c) { return a + b + c; } }; int main() { Calculator calc; cout << "10 + 20 = " << calc.add(10, 20) << endl; cout << "5.5 + 3.3 = " << calc.add(5.5, 3.3) << endl; cout << "1 + 2 + 3 = " << calc.add(1, 2, 3) << endl; return 0; }

Output:

10 + 20 = 30 5.5 + 3.3 = 8.8 1 + 2 + 3 = 6

Runtime Polymorphism Example:

#include <iostream> using namespace std; class Animal { public: virtual void makeSound() { cout << "Some generic animal sound" << endl; } }; class Dog : public Animal { public: void makeSound() override { cout << "Woof! Woof!" << endl; } }; class Cat : public Animal { public: void makeSound() override { cout << "Meow! Meow!" << endl; } }; int main() { Animal* animal1 = new Dog(); Animal* animal2 = new Cat(); animal1->makeSound(); // Calls Dog's makeSound() animal2->makeSound(); // Calls Cat's makeSound() delete animal1; delete animal2; return 0; }

Output:

Woof! Woof! Meow! Meow!

Real-World Banking System Example

Combining all OOP concepts:

#include <iostream> #include <string> using namespace std; // Abstract base class (Abstraction) class Account { protected: string accountNumber; string holderName; double balance; public: Account(string accNum, string name, double bal) : accountNumber(accNum), holderName(name), balance(bal) {} // Encapsulation - getters string getAccountNumber() { return accountNumber; } string getHolderName() { return holderName; } double getBalance() { return balance; } // Pure virtual function (Abstraction) virtual void displayInfo() = 0; void deposit(double amount) { if (amount > 0) { balance += amount; cout << "Deposited: $" << amount << endl; } } virtual void withdraw(double amount) = 0; }; // Derived class (Inheritance) class SavingsAccount : public Account { private: double interestRate; public: SavingsAccount(string accNum, string name, double bal, double rate) : Account(accNum, name, bal), interestRate(rate) {} void displayInfo() override { cout << "=== Savings Account ===" << endl; cout << "Account Number: " << accountNumber << endl; cout << "Holder: " << holderName << endl; cout << "Balance: $" << balance << endl; cout << "Interest Rate: " << interestRate << "%" << endl; } void withdraw(double amount) override { if (amount > 0 && amount <= balance) { balance -= amount; cout << "Withdrawn: $" << amount << endl; } else { cout << "Insufficient balance!" << endl; } } void addInterest() { double interest = balance * (interestRate / 100); balance += interest; cout << "Interest added: $" << interest << endl; } }; // Another derived class (Inheritance) class CheckingAccount : public Account { private: double overdraftLimit; public: CheckingAccount(string accNum, string name, double bal, double overdraft) : Account(accNum, name, bal), overdraftLimit(overdraft) {} void displayInfo() override { cout << "=== Checking Account ===" << endl; cout << "Account Number: " << accountNumber << endl; cout << "Holder: " << holderName << endl; cout << "Balance: $" << balance << endl; cout << "Overdraft Limit: $" << overdraftLimit << endl; } void withdraw(double amount) override { if (amount > 0 && (balance + overdraftLimit) >= amount) { balance -= amount; cout << "Withdrawn: $" << amount << endl; } else { cout << "Exceeds overdraft limit!" << endl; } } }; int main() { SavingsAccount savings("SAV001", "Alice", 1000, 3.5); savings.displayInfo(); savings.deposit(500); savings.addInterest(); cout << "New Balance: $" << savings.getBalance() << endl; cout << "\n"; CheckingAccount checking("CHK001", "Bob", 500, 200); checking.displayInfo(); checking.withdraw(600); // Uses overdraft cout << "New Balance: $" << checking.getBalance() << endl; return 0; }

Benefits of OOP

  1. Modularity: Code is organized into independent objects
  2. Reusability: Classes can be reused across different programs
  3. Maintainability: Easy to update and modify
  4. Security: Data hiding through encapsulation
  5. Scalability: Easy to add new features

OOP vs Procedural Programming

OOPProcedural
Based on objectsBased on functions
Data and methods togetherSeparate data and functions
Bottom-up approachTop-down approach
More secure (encapsulation)Less secure
Example: C++, JavaExample: C, Pascal

Best Practices

  1. Use encapsulation: Keep data members private
  2. Program to an interface: Use abstract classes/interfaces
  3. Favor composition over inheritance: When possible
  4. Keep classes focused: Single Responsibility Principle
  5. Use meaningful names: Clear class and method names

Practice Exercises

  1. Library System: Create classes for Book, Member, and Library with proper encapsulation

  2. Shape Hierarchy: Implement abstract Shape class with Circle, Rectangle, Triangle

  3. Vehicle System: Create base Vehicle class and derive Car, Bike, Truck with polymorphism

  4. Employee Management: Implement Employee hierarchy with different types (Manager, Developer, etc.)

  5. E-commerce: Design Product, Cart, and Order classes with proper OOP principles

OOP principles are essential for writing professional, maintainable C++ code!

Last updated on