Skip to main content

2. Types of Inheritance and Method Overriding

2.1 Single Inheritance

Definition: One derived class inherits from one base class.

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

class Person {
protected:
    string name;
    int age;
    
public:
    Person(string n, int a) : name(n), age(a) {}
    
    void introduce() {
        cout << "Hi, I'm " << name << ", " << age << " years old." << endl;
    }
};

class Student : public Person {
private:
    string studentId;
    double gpa;
    
public:
    Student(string n, int a, string id, double g)
        : Person(n, a), studentId(id), gpa(g) {}
    
    void study() {
        cout << name << " is studying..." << endl;
    }
    
    void showGPA() {
        cout << "GPA: " << gpa << endl;
    }
};

int main() {
    Student s("Alice", 20, "S001", 3.8);
    s.introduce();  // Inherited
    s.study();      // Own method
    s.showGPA();    // Own method
    
    return 0;
}

2.2 Multilevel Inheritance

Definition: A class is derived from another derived class.

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

// Level 1: Base class
class LivingBeing {
protected:
    bool isAlive;
    
public:
    LivingBeing() : isAlive(true) {
        cout << "LivingBeing created" << endl;
    }
    
    void breathe() {
        cout << "Breathing..." << endl;
    }
};

// Level 2: Derived from LivingBeing
class Animal : public LivingBeing {
protected:
    string species;
    
public:
    Animal(string s) : species(s) {
        cout << "Animal created: " << species << endl;
    }
    
    void move() {
        cout << species << " is moving..." << endl;
    }
};

// Level 3: Derived from Animal
class Dog : public Animal {
private:
    string name;
    
public:
    Dog(string n) : Animal("Canine"), name(n) {
        cout << "Dog created: " << name << endl;
    }
    
    void bark() {
        cout << name << " is barking!" << endl;
    }
    
    void showCapabilities() {
        breathe();  // From LivingBeing
        move();     // From Animal
        bark();     // From Dog
    }
};

int main() {
    Dog myDog("Buddy");
    cout << "\nDog capabilities:" << endl;
    myDog.showCapabilities();
    
    return 0;
}

Output:

LivingBeing created
Animal created: Canine
Dog created: Buddy

Dog capabilities:
Breathing...
Canine is moving...
Buddy is barking!

2.3 Multiple Inheritance

Definition: A class inherits from multiple base classes.

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

class Engine {
protected:
    int horsepower;
    
public:
    Engine(int hp) : horsepower(hp) {
        cout << "Engine: " << horsepower << " HP" << endl;
    }
    
    void start() {
        cout << "Engine started: " << horsepower << " HP" << endl;
    }
};

class GPS {
protected:
    string currentLocation;
    
public:
    GPS(string loc) : currentLocation(loc) {
        cout << "GPS initialized at: " << loc << endl;
    }
    
    void navigate(string destination) {
        cout << "Navigating from " << currentLocation 
             << " to " << destination << endl;
    }
};

class SmartCar : public Engine, public GPS {
private:
    string model;
    
public:
    SmartCar(string m, int hp, string loc) 
        : Engine(hp), GPS(loc), model(m) {
        cout << "SmartCar created: " << model << endl;
    }
    
    void drive(string destination) {
        cout << "\n=== Driving " << model << " ===" << endl;
        start();            // From Engine
        navigate(destination); // From GPS
        cout << "Arrived at destination!" << endl;
    }
};

int main() {
    SmartCar tesla("Tesla Model S", 670, "New York");
    tesla.drive("Boston");
    
    return 0;
}

Output:

Engine: 670 HP
GPS initialized at: New York
SmartCar created: Tesla Model S

=== Driving Tesla Model S ===
Engine started: 670 HP
Navigating from New York to Boston
Arrived at destination!

Diamond Problem in Multiple Inheritance:

#include <iostream>
using namespace std;

class Device {
protected:
    int powerConsumption;
    
public:
    Device(int power) : powerConsumption(power) {
        cout << "Device: " << power << "W" << endl;
    }
};

// Problem: Both inherit from Device
class Printer : public Device {
public:
    Printer(int power) : Device(power) {}
};

class Scanner : public Device {
public:
    Scanner(int power) : Device(power) {}
};

// This creates two copies of Device!
class AllInOne : public Printer, public Scanner {
public:
    AllInOne(int pPower, int sPower) 
        : Printer(pPower), Scanner(sPower) {}
    // Now we have ambiguity!
};

// Solution: Virtual Inheritance
class DeviceVirtual {
protected:
    int powerConsumption;
    
public:
    DeviceVirtual(int power) : powerConsumption(power) {
        cout << "Device: " << power << "W" << endl;
    }
};

class PrinterVirtual : virtual public DeviceVirtual {
public:
    PrinterVirtual(int power) : DeviceVirtual(power) {}
};

class ScannerVirtual : virtual public DeviceVirtual {
public:
    ScannerVirtual(int power) : DeviceVirtual(power) {}
};

class AllInOneVirtual : public PrinterVirtual, public ScannerVirtual {
public:
    AllInOneVirtual(int power) 
        : DeviceVirtual(power), PrinterVirtual(power), ScannerVirtual(power) {}
    // Now only ONE copy of DeviceVirtual
};

int main() {
    AllInOneVirtual device(50);
    
    return 0;
}

2.4 Hierarchical Inheritance

Definition: Multiple derived classes inherit from a single base class.

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

class Shape {
protected:
    string color;
    
public:
    Shape(string c) : color(c) {}
    
    void displayColor() {
        cout << "Color: " << color << endl;
    }
    
    virtual double getArea() = 0;
};

class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(string c, double r) : Shape(c), radius(r) {}
    
    double getArea() override {
        return 3.14159 * radius * radius;
    }
    
    void display() {
        cout << "Circle - ";
        displayColor();
        cout << "Radius: " << radius << endl;
        cout << "Area: " << getArea() << endl;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(string c, double w, double h) 
        : Shape(c), width(w), height(h) {}
    
    double getArea() override {
        return width * height;
    }
    
    void display() {
        cout << "Rectangle - ";
        displayColor();
        cout << "Width: " << width << ", Height: " << height << endl;
        cout << "Area: " << getArea() << endl;
    }
};

class Triangle : public Shape {
private:
    double base, height;
    
public:
    Triangle(string c, double b, double h) 
        : Shape(c), base(b), height(h) {}
    
    double getArea() override {
        return 0.5 * base * height;
    }
    
    void display() {
        cout << "Triangle - ";
        displayColor();
        cout << "Base: " << base << ", Height: " << height << endl;
        cout << "Area: " << getArea() << endl;
    }
};

int main() {
    Circle circle("Red", 5.0);
    Rectangle rect("Blue", 4.0, 6.0);
    Triangle tri("Green", 8.0, 5.0);
    
    circle.display();
    cout << endl;
    rect.display();
    cout << endl;
    tri.display();
    
    return 0;
}

2.5 Method Overriding

Definition: Redefining a base class method in a derived class.

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

class Account {
protected:
    string accountNumber;
    double balance;
    
public:
    Account(string acc, double bal) 
        : accountNumber(acc), balance(bal) {}
    
    // Method to be overridden
    virtual void withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
        } else {
            cout << "Insufficient funds!" << endl;
        }
    }
    
    virtual void displayInfo() {
        cout << "Account: " << accountNumber << endl;
        cout << "Balance: $" << balance << endl;
    }
    
    double getBalance() { return balance; }
};

class SavingsAccount : public Account {
private:
    double minimumBalance;
    
public:
    SavingsAccount(string acc, double bal, double minBal)
        : Account(acc, bal), minimumBalance(minBal) {}
    
    // Override withdraw with additional constraint
    void withdraw(double amount) override {
        if (balance - amount >= minimumBalance) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
        } else {
            cout << "Cannot withdraw: Minimum balance requirement!" << endl;
            cout << "Minimum balance: $" << minimumBalance << endl;
        }
    }
    
    void displayInfo() override {
        Account::displayInfo();  // Call base class method
        cout << "Minimum Balance: $" << minimumBalance << endl;
        cout << "Account Type: Savings" << endl;
    }
};

class CheckingAccount : public Account {
private:
    double overdraftLimit;
    
public:
    CheckingAccount(string acc, double bal, double overdraft)
        : Account(acc, bal), overdraftLimit(overdraft) {}
    
    // Override withdraw with overdraft feature
    void withdraw(double amount) override {
        if (balance + overdraftLimit >= amount) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
            if (balance < 0) {
                cout << "Warning: Overdraft used! Balance: $" << balance << endl;
            }
        } else {
            cout << "Cannot withdraw: Exceeds overdraft limit!" << endl;
        }
    }
    
    void displayInfo() override {
        Account::displayInfo();
        cout << "Overdraft Limit: $" << overdraftLimit << endl;
        cout << "Account Type: Checking" << endl;
    }
};

int main() {
    SavingsAccount savings("SA001", 5000, 1000);
    CheckingAccount checking("CA001", 2000, 500);
    
    cout << "=== Savings Account ===" << endl;
    savings.displayInfo();
    cout << "\nTrying to withdraw $4500..." << endl;
    savings.withdraw(4500);  // Should fail (below minimum)
    cout << "\nTrying to withdraw $3000..." << endl;
    savings.withdraw(3000);  // Should succeed
    
    cout << "\n=== Checking Account ===" << endl;
    checking.displayInfo();
    cout << "\nTrying to withdraw $2300..." << endl;
    checking.withdraw(2300);  // Should succeed with overdraft
    
    return 0;
}