BIT153 Object Oriented Programming

Object Oriented ProgrammingUnit 115 min read

OOP Basics: Paradigms, Principles & Real-World Models

Unit 1 of Object Oriented Programming introduces the core concepts of OOP—its definition, principles (encapsulation, inheritance, polymorphism, abstraction), and how it differs from procedural programming. This note covers real-world applications, key definitions, visual models of OOP structures, and exam-focused compa

TAKEAWAYS:

  • OOP models real-world entities as objects (data + behavior) instead of functions, making code more modular and reusable.
  • The four pillars of OOP (encapsulation, inheritance, polymorphism, abstraction) solve common software problems like code duplication and complexity.
  • OOP differs from procedural programming in organization (objects vs. functions), reusability (inheritance vs. libraries), and data hiding (private members vs. global variables).
  • Encapsulation bundles data and methods into a single unit (class) and restricts direct access via access modifiers (private, public, protected).
  • Abstraction hides complex implementation details, exposing only essential features (e.g., vector.push_back() hides memory management).
  • Inheritance and polymorphism enable hierarchical classification (e.g., Animal → Dog → Labrador) and flexible method overriding, respectively.

1. What is Object-Oriented Programming (OOP)?

OOP is a programming paradigm that organizes software design around objects (instances of classes) rather than functions and logic. It models real-world entities as interactive components with:

  • Attributes (data/properties, e.g., name, salary).
  • Methods (functions/behaviors, e.g., calculateSalary(), display()).

Key Idea: Modeling Real-World Systems

Unlike procedural programming (which focuses on writing procedures/functions), OOP focuses on data and how it interacts. For example:

  • Procedural Approach: Write functions like calculateSalary(empId, hours).
  • OOP Approach: Create an Employee object with salary (data) and calculateSalary() (method).

2. OOP vs. Procedural Programming: A Comparison

Feature OOP Procedural Programming
Focus Objects/data Functions/logic
Code Organization Classes → Objects Functions → Procedures
Data Access Encapsulated (private/public) Global/local variables
Reusability Inheritance, polymorphism Function libraries
Modularity High (objects are self-contained) Lower (functions depend on global data)
Example Car class with accelerate() accelerate(carSpeed) function

Why OOP?

  • Modularity: Easier to maintain and debug (e.g., updating Employee class affects all Employee objects).
  • Reusability: Inheritance avoids rewriting code (e.g., Dog inherits from Animal).
  • Scalability: Handles complex systems better (e.g., a bank’s Account hierarchy: SavingsAccount, LoanAccount).

3. The Four Pillars of OOP

(A) Encapsulation: Data Hiding and Bundling

Definition: Bundling data (attributes) and methods (functions) into a single unit (class) and restricting direct access via access modifiers.

  • Private: Accessible only within the class.
  • Public: Accessible everywhere.
  • Protected: Accessible within the class and derived classes.

Example: Bank Account

class Account {
private:
    double balance; // Hidden from outside
public:
    void deposit(double amount) { balance += amount; }
    void withdraw(double amount) {
        if (amount <= balance) balance -= amount;
    }
    double getBalance() { return balance; } // Controlled access
};

Visual: Encapsulation in a Bank Account

classDiagram
    class Account {
        -balance: double
        +deposit(amount: double)
        +withdraw(amount: double)
        +getBalance(): double
    }
    Account --> "1" balance : hides

Real-World Tie-In:

  • eSewa/Khalti: Your transaction balance is encapsulated. Only eSewa’s methods (e.g., transfer(), checkBalance()) can modify it, preventing fraudulent access.

(B) Inheritance: Hierarchical Classification

Definition: Mechanism to create a new class (derived/subclass) from an existing class (base/superclass), inheriting its properties and behaviors.

  • Types:
    • Single: One base class (e.g., Dog → Animal).
    • Multiple: Multiple base classes (C++ supports via interfaces).
    • Multilevel: Chain of inheritance (e.g., Vehicle → Car → SportsCar).

Example: Employee Hierarchy

class Employee { // Base class
protected:
    string name;
    int id;
public:
    void display() { cout << "ID: " << id << ", Name: " << name; }
};

class Manager : public Employee { // Derived class
public:
    void manageTeam() { cout << name << " manages a team."; }
};

Visual: Inheritance Tree for Employees

TeamLeadProjectManagerManagerFrontendBackendDeveloperEmployee
Hierarchy: Employee → Manager/Developer → Specializations

Real-World Tie-In:

  • Ncell/NTCLoan: Customer (base) → PrepaidCustomer/PostpaidCustomer (derived). Shared methods like checkBalance() are inherited, while recharge() is unique to PrepaidCustomer.

(C) Polymorphism: "Many Forms"

Definition: Ability of an object to take multiple forms. Two types:

  1. Compile-time (Static): Achieved via function overloading or operator overloading.
  2. Run-time (Dynamic): Achieved via virtual functions and method overriding.

Example: Shape Hierarchy (Dynamic Polymorphism)

class Shape {
public:
    virtual void draw() { cout << "Drawing a shape"; }
};

class Circle : public Shape {
public:
    void draw() override { cout << "Drawing a circle"; }
};

int main() {
    Shape* s = new Circle();
    s->draw(); // Output: "Drawing a circle" (runtime decision)
}

Visual: Polymorphism in Action

classDiagram
  class Shape {
    +draw()
  }
  class Circle {
    +draw()
  }
  class Square {
    +draw()
  }
  Shape <|-- Circle : overrides
  Shape <|-- Square : overrides
  note for Shape "Base class\nRuntime polymorphism"
  note for Circle "Concrete implementation"
  note for Square "Concrete implementation"

Real-World Tie-In:

  • Pathao/Daraz: Order (base) → FoodOrder/ProductOrder (derived). The processOrder() method behaves differently for each type (e.g., FoodOrder may call a restaurant API, while ProductOrder updates inventory).

(D) Abstraction: Hiding Complexity

Definition: Showing only essential features and hiding implementation details.

  • Achieved via:
    • Abstract classes (classes with at least one pure virtual function).
    • Interfaces (pure abstract classes in C++).

Example: Payment System

class PaymentMethod {
public:
    virtual void pay(double amount) = 0; // Pure virtual function
};

class CreditCard : public PaymentMethod {
public:
    void pay(double amount) override { cout << "Paid $" << amount << " via credit card"; }
};

Visual: Abstraction in Payment Methods

classDiagram
    class PaymentMethod {
        <<abstract>>
        +pay(amount: double) = 0
    }
    class CreditCard {
        +pay(amount: double)
    }
    PaymentMethod <|-- CreditCard : implements

Real-World Tie-In:

  • Khalti/eSewa: Users interact with pay() without knowing whether it uses UPI, credit card, or bank transfer. The abstraction hides the underlying logic.

4. Why Use OOP? Advantages and Disadvantages

Advantages

Benefit Explanation
Modularity Code is organized into objects, making it easier to update/maintain.
Reusability Inheritance reduces redundant code (e.g., Animal class reused for Dog, Cat).
Scalability Handles large projects (e.g., a bank’s Account system with 100+ classes).
Security Encapsulation protects data (e.g., private salary in Employee class).
Real-World Modeling Directly maps to real systems (e.g., Car → Engine, Wheels).

Disadvantages

Limitation Explanation
Complexity Steeper learning curve than procedural programming.
Performance Overhead Inheritance can slow down execution (though modern compilers optimize this).
Design Overhead Requires careful planning (e.g., deciding class hierarchies).

5. OOP in Action: A Worked Example

Problem: Model a Library System with Book and Member classes, where Member can borrow Book. Solution:

#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    bool isAvailable;
public:
    Book(string t) : title(t), isAvailable(true) {}
    void borrow() { isAvailable = false; }
    void returnBook() { isAvailable = true; }
    string getTitle() { return title; }
    bool available() { return isAvailable; }
};

class Member {
private:
    string name;
public:
    Member(string n) : name(n) {}
    void borrowBook(Book& book) {
        if (book.available()) {
            book.borrow();
            cout << name << " borrowed " << book.getTitle() << endl;
        } else {
            cout << "Book is not available!" << endl;
        }
    }
};

int main() {
    Book cppBook("OOP in C++");
    Member alice("Alice");
    alice.borrowBook(cppBook); // Output: Alice borrowed OOP in C++
    alice.borrowBook(cppBook); // Output: Book is not available!
}

Visual: State After Borrowing

classDiagram
    class Book {
        -title: string
        -isAvailable: bool
        +borrow()
        +returnBook()
        +getTitle(): string
    }
    class Member {
        -name: string
        +borrowBook(book: Book)
    }
    Member --> Book : borrows

Real-World Tie-In:

  • Central Library Management System: The Book class encapsulates availability status, while Member methods handle borrowing/returns. The system scales for thousands of books and members.

6. Common Misconceptions

  1. "OOP is only for C++/Java"
    • Reality: OOP concepts apply to all languages (even Python, which is OOP by default). The syntax varies, but the principles remain.
OOPEncapsulationInheritancePolymorphismAbstraction
The 4 Pillars as interconnected concepts (not standalone)
  1. "Inheritance is always better"

    • Reality: Overuse leads to tight coupling. Prefer composition (e.g., Car has an Engine object) over deep inheritance hierarchies.
  2. "Polymorphism is just function overloading"

    • Reality: Polymorphism includes runtime binding (e.g., virtual functions), which enables flexible behavior (e.g., Shape → Circle/Square).

7. Exam Tip: How to Score Full Marks

  1. Define Clearly:

    • Start with precise definitions (e.g., "Encapsulation is the mechanism to bind data and methods into a single unit while restricting direct access via access modifiers.").
  2. Use Diagrams:

    • Draw class diagrams for inheritance/polymorphism (e.g., Animal → Dog → Labrador).
    • Show state transitions (e.g., Book before/after borrow()).
  3. Compare OOP vs. Procedural:

    • Use a table (as above) to highlight differences in focus, reusability, and modularity.
  4. Code + Trace:

    • For questions like "Explain polymorphism with an example", provide:
      • A code snippet (e.g., Shape hierarchy).
      • A trace table showing runtime behavior (e.g., Circle::draw() called via Shape* pointer).
  5. Real-World Links:

    • Relate examples to Nepali apps (e.g., "Khalti uses abstraction to hide payment gateways like Visa/Mastercard").
  6. Avoid Vague Answers:

    • ❌ "OOP is better because it’s object-oriented."
    • ✅ "OOP improves maintainability via encapsulation (e.g., private salary in Employee class) and reusability via inheritance (e.g., Manager inherits display() from Employee)."

8. Past Exam Questions Solved

Question 1: "Can we use OOP concepts using structures instead of classes? Justify your opinion."

Answer: No, structures (struct) in C++ cannot fully replace classes for OOP because:

  1. Default Access: struct members are public by default, while class members are private. OOP requires encapsulation (data hiding).
  2. Methods: struct cannot have member functions without explicitly declaring them outside (unlike class).
  3. Inheritance: struct supports inheritance, but the lack of private members limits proper OOP design.

Visual: struct vs. class

classDiagram
    class Struct {
        +data: int
        +method() : void
    }
    class Class {
        -data: int
        +method() : void
    }
    note for Struct "Default: public\nNo encapsulation"
    note for Class "Default: private\nSupports OOP"

Question 2: "Explain the chain of constructor and destructor between subclasses and superclasses during inheritance."

Answer: When an object of a derived class is created/destroyed, constructors/destructors execute in this order:

  1. Base class constructor → Derived class constructor (top-down).
  2. Derived class destructor → Base class destructor (bottom-up).

Example:

class Base {
public:
    Base() { cout << "Base constructor"; }
    ~Base() { cout << "Base destructor"; }
};

class Derived : public Base {
public:
    Derived() { cout << "Derived constructor"; }
    ~Derived() { cout << "Derived destructor"; }
};

int main() {
    Derived d;
    // Output:
    // Base constructor
    // Derived constructor
    // Derived destructor
    // Base destructor
}

Visual: Constructor/Destructor Chain

flowchart TD
  A["Base Constructor"] --> B["Derived Constructor"]
  B --> C["Derived Methods"]
  C --> D["Derived Destructor"]
  D --> E["Base Destructor"]

9. In the Real World

  1. eSewa/Khalti (Payment Systems)

    • Concept: Abstraction + Polymorphism
    • How: The PaymentMethod abstract class defines pay(), with derived classes (CreditCard, UPI) implementing it. Users interact with pay() without knowing the underlying method (e.g., CreditCard::pay() vs. UPI::pay()).
  2. Daraz/Pathao (Order Processing)

    • Concept: Inheritance + Encapsulation
    • How: Order (base) has process() and cancel(). Derived classes like FoodOrder override process() to call restaurant APIs, while ProductOrder updates inventory. The status (e.g., "Processing") is private to prevent invalid updates.
  3. Nepal Stock Exchange (NEPSE) Trading System

    • Concept: Polymorphism
    • How: Trade (base) has execute(). Derived classes (BuyTrade, SellTrade) override execute() to handle different brokerage rules. The system routes trades dynamically based on the object type.

10. Common Pitfalls in Exams

  1. Ignoring Access Modifiers:

    • ❌ "Encapsulation is just bundling data and methods."
    • ✅ "Encapsulation bundles data/methods and restricts access via private/public."
  2. Confusing Polymorphism Types:

    • ❌ "Polymorphism is only function overloading."
    • ✅ "Polymorphism includes compile-time (overloading) and runtime (virtual functions) forms."
  3. Poor Diagrams:

    • ❌ Text-only answers for inheritance.
    • ✅ Always draw class diagrams with arrows (<|-- for inheritance).
  4. Overlooking Real-World Examples:

    • ❌ Generic examples like "a car and engine."
    • ✅ Tie to Nepali apps (e.g., "Pathao’s Order hierarchy uses polymorphism to route deliveries differently for food vs. goods.").

11. Quick Revision Checklist

Before the exam, ensure you can:

  • Define the four pillars of OOP and give one example each.
  • Draw a class diagram for inheritance (e.g., Animal → Dog → Labrador).
  • Explain encapsulation with a BankAccount example.
  • Differentiate procedural vs. OOP in a table.
  • Write a polymorphic code snippet (e.g., Shape hierarchy) and trace its execution.
  • Link two OOP concepts to a real-world Nepali app (e.g., Khalti’s abstraction, Daraz’s inheritance).

Based on the TU BIT syllabus for Object Oriented Programming (BIT153), unit 1.

Discussion

Loading…