Inheritance and Polymorphism: The Power of Hierarchies

What is Inheritance?

Inheritance is like a family tree - children inherit traits from their parents. In programming, classes can inherit properties and behaviors from other classes. A "Car" is a type of "Vehicle", a "Dog" is a type of "Animal"!

Types of Inheritance

graph TD A[Inheritance Types] --> B[Public Inheritance] A --> C[Protected Inheritance] A --> D[Private Inheritance] B --> E["Most common
IS-A relationship
Public stays public"] C --> F["Less common
Public becomes protected"] D --> G["Rare
Everything becomes private"] style B fill:#4CAF50 style C fill:#FF9800 style D fill:#F44336

Basic Inheritance Example

// Base class (Parent)
class Animal {
protected:  // Accessible to derived classes
    string name;
    int age;
    
public:
    Animal(string n, int a) : name(n), age(a) {
        cout << "Animal constructor" << endl;
    }
    
    void eat() {
        cout << name << " is eating." << endl;
    }
    
    void sleep() {
        cout << name << " is sleeping." << endl;
    }
    
    void displayInfo() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

// Derived class (Child)
class Dog : public Animal {  // Public inheritance
private:
    string breed;
    
public:
    // Constructor calls base constructor
    Dog(string n, int a, string b) : Animal(n, a), breed(b) {
        cout << "Dog constructor" << endl;
    }
    
    // Additional method
    void bark() {
        cout << name << " says: Woof! Woof!" << endl;
    }
    
    // Can access protected members
    void wagTail() {
        cout << name << " is wagging tail happily!" << endl;
    }
    
    void displayInfo() {
        Animal::displayInfo();  // Call base version
        cout << "Breed: " << breed << endl;
    }
};

// Usage
int main() {
    Dog myDog("Buddy", 3, "Golden Retriever");
    
    myDog.eat();         // Inherited from Animal
    myDog.sleep();       // Inherited from Animal
    myDog.bark();        // Dog's own method
    myDog.displayInfo(); // Overridden method
    
    return 0;
}

Access Levels in Inheritance

Think of access levels like security clearance - some information is public, some is classified for family only (protected), and some is top secret (private)!

Access Control in Inheritance Base Class public: accessible everywhere protected: base + derived private: base only Public Inheritance: ✓ public → public ✓ protected → protected ✗ private → not accessible Private Inheritance: ✓ public → private ✓ protected → private ✗ private → not accessible

Constructor and Destructor Order

Construction is like building a house - foundation first (base), then walls (derived). Destruction is the reverse - tear down walls first, then foundation!

What is Polymorphism?

Polymorphism means "many forms" - like how a remote control's "play" button works for DVD players, streaming devices, and game consoles. One interface, multiple implementations!

graph TD A[Polymorphism] --> B[Compile-Time] A --> C[Runtime] B --> D[Function Overloading] B --> E[Operator Overloading] C --> F[Virtual Functions] C --> G[Abstract Classes] C --> H[Interfaces] style C fill:#4CAF50 style F fill:#4CAF50 style G fill:#4CAF50

Virtual Functions: The Key to Polymorphism

Virtual functions are like job descriptions - the base class says "here's what needs to be done" and derived classes say "here's how I do it"!

Virtual Function Mechanism Shape virtual draw() virtual area() Circle draw() → ⭕ area() → πr² Rectangle draw() → ▭ area() → w×h Triangle draw() → △ area() → ½bh Shape* ptr = new Circle(); ptr->draw(); // Calls Circle's draw!

Virtual Functions Example

class Shape {
protected:
    string color;
    
public:
    Shape(string c = "black") : color(c) {}
    
    // Virtual functions - can be overridden
    virtual void draw() {
        cout << "Drawing a shape" << endl;
    }
    
    virtual double area() {
        return 0;  // Default implementation
    }
    
    // Non-virtual function
    void setColor(string c) {
        color = c;
    }
    
    // Virtual destructor - important!
    virtual ~Shape() {
        cout << "Shape destructor" << endl;
    }
};

class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r, string c = "black") : Shape(c), radius(r) {}
    
    // Override virtual functions
    void draw() override {  // 'override' keyword for safety
        cout << "Drawing a " << color << " circle with radius " << radius << endl;
    }
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    ~Circle() {
        cout << "Circle destructor" << endl;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(double w, double h, string c = "black") 
        : Shape(c), width(w), height(h) {}
    
    void draw() override {
        cout << "Drawing a " << color << " rectangle " 
             << width << "x" << height << endl;
    }
    
    double area() override {
        return width * height;
    }
};

// Polymorphism in action!
void processShape(Shape* shape) {
    shape->draw();
    cout << "Area: " << shape->area() << endl;
    cout << "---" << endl;
}

int main() {
    // Array of different shapes
    Shape* shapes[3];
    shapes[0] = new Circle(5, "red");
    shapes[1] = new Rectangle(4, 6, "blue");
    shapes[2] = new Circle(3, "green");
    
    // Process all shapes polymorphically
    for (int i = 0; i < 3; i++) {
        processShape(shapes[i]);
    }
    
    // Clean up
    for (int i = 0; i < 3; i++) {
        delete shapes[i];  // Calls correct destructor!
    }
    
    return 0;
}

Abstract Classes and Pure Virtual Functions

Abstract classes are like contracts - they define what must be done but not how. You can't build a generic "Vehicle", but you can build a "Car" or "Bike"!

Abstract Class Example

// Abstract base class
class GameCharacter {
protected:
    string name;
    int health;
    int level;
    
public:
    GameCharacter(string n, int h, int l) 
        : name(n), health(h), level(l) {}
    
    // Pure virtual functions - MUST be implemented by derived classes
    virtual void attack() = 0;
    virtual void defend() = 0;
    virtual void specialAbility() = 0;
    
    // Regular virtual function - CAN be overridden
    virtual void takeDamage(int damage) {
        health -= damage;
        if (health < 0) health = 0;
        cout << name << " takes " << damage << " damage!" << endl;
    }
    
    // Non-virtual functions
    void displayStats() {
        cout << "=== " << name << " ===" << endl;
        cout << "Level: " << level << endl;
        cout << "Health: " << health << endl;
    }
    
    virtual ~GameCharacter() {}
};

// Concrete derived class
class Warrior : public GameCharacter {
private:
    int armor;
    
public:
    Warrior(string n) : GameCharacter(n, 100, 1), armor(50) {}
    
    void attack() override {
        cout << name << " swings sword for heavy damage!" << endl;
    }
    
    void defend() override {
        cout << name << " raises shield, reducing damage by " 
             << armor << "%!" << endl;
    }
    
    void specialAbility() override {
        cout << name << " enters RAGE mode! Attack doubled!" << endl;
    }
    
    void takeDamage(int damage) override {
        int reducedDamage = damage * (100 - armor) / 100;
        GameCharacter::takeDamage(reducedDamage);
    }
};

class Mage : public GameCharacter {
private:
    int mana;
    
public:
    Mage(string n) : GameCharacter(n, 70, 1), mana(100) {}
    
    void attack() override {
        if (mana >= 10) {
            cout << name << " casts fireball!" << endl;
            mana -= 10;
        } else {
            cout << name << " is out of mana!" << endl;
        }
    }
    
    void defend() override {
        cout << name << " casts magic shield!" << endl;
    }
    
    void specialAbility() override {
        cout << name << " summons meteor shower!" << endl;
        mana = 0;  // Uses all mana
    }
};

Multiple Inheritance and the Diamond Problem

Multiple inheritance is like having multiple parents - it can get complicated! The diamond problem occurs when a class inherits from two classes that share a common base.

The Diamond Problem Device id: int Printer print() Scanner scan() AllInOne copy() ⚠️ Problem: Which Device::id? ✓ Solution: Virtual inheritance

Dynamic Casting and Type Checking

Dynamic casting is like checking someone's ID - you want to make sure they really are who they claim to be before giving them special access!

class Employee {
protected:
    string name;
    int id;
    
public:
    Employee(string n, int i) : name(n), id(i) {}
    virtual void work() {
        cout << name << " is working." << endl;
    }
    virtual ~Employee() {}
};

class Manager : public Employee {
private:
    vector team;
    
public:
    Manager(string n, int i) : Employee(n, i) {}
    
    void work() override {
        cout << name << " is managing the team." << endl;
    }
    
    void conductMeeting() {
        cout << name << " is conducting a meeting." << endl;
    }
    
    void addTeamMember(Employee* emp) {
        team.push_back(emp);
    }
};

class Developer : public Employee {
private:
    string programmingLanguage;
    
public:
    Developer(string n, int i, string lang) 
        : Employee(n, i), programmingLanguage(lang) {}
    
    void work() override {
        cout << name << " is coding in " << programmingLanguage << endl;
    }
    
    void debug() {
        cout << name << " is debugging code." << endl;
    }
};

// Using dynamic_cast
void processEmployee(Employee* emp) {
    emp->work();  // Polymorphic call
    
    // Try to cast to Manager
    Manager* mgr = dynamic_cast(emp);
    if (mgr != nullptr) {
        mgr->conductMeeting();  // Manager-specific method
    }
    
    // Try to cast to Developer
    Developer* dev = dynamic_cast(emp);
    if (dev != nullptr) {
        dev->debug();  // Developer-specific method
    }
}

Practice Exercise: Zoo Management System

Build a Polymorphic Zoo

Create a zoo management system using inheritance and polymorphism:

  1. Abstract Animal base class with pure virtual functions
  2. Derived classes: Mammal, Bird, Reptile
  3. Specific animals: Lion, Eagle, Snake, etc.
  4. Polymorphic feeding and care functions
  5. Visitor pattern for zoo tours
class Animal {
protected:
    string name;
    int age;
    double weight;
    
public:
    Animal(string n, int a, double w) 
        : name(n), age(a), weight(w) {}
    
    // Pure virtual functions
    virtual void makeSound() = 0;
    virtual void eat() = 0;
    virtual string getHabitat() = 0;
    
    // TODO: Add more virtual functions
    
    virtual ~Animal() {}
};

class Mammal : public Animal {
    // TODO: Implement mammal-specific behavior
};

class Bird : public Animal {
private:
    double wingspan;
    // TODO: Implement bird-specific behavior
};

class Zoo {
private:
    vector animals;
    
public:
    void addAnimal(Animal* animal);
    void feedAllAnimals();
    void conductTour();
    // TODO: Complete implementation
};
Implementation Hints

Virtual Function Table (VTable)

Behind the scenes, C++ uses a virtual function table - like a phone directory that tells the program which function to call!

Best Practices for Inheritance

graph TD A[Best Practices] --> B[Virtual Destructor] A --> C[Override Keyword] A --> D[Prefer Composition] A --> E[Liskov Substitution] B --> F[Always in base class
with virtual functions] C --> G[Catch errors
at compile time] D --> H[Has-a vs Is-a] E --> I[Derived should work
everywhere base works]

Challenge Exercise: Game Engine

Advanced Polymorphism Challenge

Build a simple game engine framework:

  1. GameObject base class with position and rendering
  2. Updateable interface for objects that move
  3. Collidable interface for collision detection
  4. Multiple inheritance for complex objects
  5. Scene manager using polymorphism
Framework Structure
class GameObject {
protected:
    float x, y;
    bool visible;
    
public:
    virtual void render() = 0;
    virtual ~GameObject() {}
};

class Updateable {
public:
    virtual void update(float deltaTime) = 0;
};

class Collidable {
public:
    virtual bool checkCollision(Collidable* other) = 0;
    virtual void onCollision(Collidable* other) = 0;
};

class Player : public GameObject, 
               public Updateable, 
               public Collidable {
    // Multiple inheritance!
};

Key Takeaways

graph LR A[Master Inheritance] --> B[Design Hierarchies] B --> C[Use Polymorphism] C --> D[Build Flexible Systems] D --> E[Expert C++ Developer!]