C++ Inheritance Object-Oriented Programming
OOP Concept

C++ Inheritance: Complete Guide with Examples

Master C++ inheritance: single, multiple, multilevel, hierarchical inheritance. Learn access specifiers, polymorphism, virtual functions, and best practices for OOP.

Single Inheritance

One Base Class

Multiple Inheritance

Multiple Base Classes

Multilevel

Chain of Inheritance

Hierarchical

Multiple Derived Classes

Introduction to Inheritance

Inheritance is a fundamental Object-Oriented Programming (OOP) concept that allows a class to acquire properties and behaviors of another class. It promotes code reusability and establishes relationships between classes.

Why Use Inheritance?
  • Code reusability and reduction
  • Establishes "is-a" relationships
  • Supports polymorphism
  • Creates hierarchical classifications
  • Extends existing functionality
  • Improves code organization
Inheritance Components
  • Base Class: Parent class being inherited from
  • Derived Class: Child class that inherits
  • Access Specifiers: public, private, protected
  • Member Functions: Inherited methods
  • Data Members: Inherited attributes
Inheritance Relationship Flow
1
Base Class: Define common properties and behaviors
2
Derived Class: Inherits from base class
3
Extension: Add new properties/methods
4
Override: Modify inherited behaviors
5
Utilization: Use inherited functionality

C++ Inheritance Types

The following table compares all inheritance types in C++ with their syntax, use cases, and characteristics:

Type Syntax When to Use Characteristics
Single Inheritance class Derived : public Base { }; Simple "is-a" relationships, basic reuse One base class, one derived class
Multiple Inheritance class Derived : public Base1, public Base2 { }; Combine features from multiple classes Multiple base classes, one derived class
Multilevel Inheritance class A {}; class B: public A {}; class C: public B {}; Hierarchical systems, layered abstractions Chain of inheritance (grandparent-parent-child)
Hierarchical Inheritance class Base {}; class D1: public Base {}; class D2: public Base {}; Multiple specialized classes from one base One base class, multiple derived classes
Hybrid Inheritance Combination of multiple types Complex class hierarchies, special cases Multiple + hierarchical, uses virtual inheritance
Virtual Inheritance class Derived : virtual public Base { }; Solve diamond problem in multiple inheritance Prevents duplicate base class instances

1. Access Specifiers in Inheritance

Access specifiers determine how base class members are accessible in derived classes. C++ provides three access specifiers: public, protected, and private.

Access Specifier Syntax
// Base class
class Base {
public:
    int publicVar;
protected:
    int protectedVar;
private:
    int privateVar;
};

// Derived class with different access modes
class Derived : public Base {
    // public inheritance:
    // publicVar remains public
    // protectedVar remains protected
    // privateVar is inaccessible
};

class Derived : protected Base {
    // protected inheritance:
    // publicVar becomes protected
    // protectedVar remains protected
    // privateVar is inaccessible
};

class Derived : private Base {
    // private inheritance:
    // publicVar becomes private
    // protectedVar becomes private
    // privateVar is inaccessible
}
Access Specifier Examples
#include <iostream>
using namespace std;

// Base class demonstrating different access levels
class Animal {
public:
    string name;
    
    void speak() {
        cout << name << " makes a sound." << endl;
    }
    
protected:
    string species;
    
    void setSpecies(string s) {
        species = s;
    }
    
private:
    int age;
    
    void setAge(int a) {
        age = a;
    }
};

// Public Inheritance
class Dog : public Animal {
public:
    Dog(string n) {
        name = n;           // Accessible (public in base)
        setSpecies("Dog");  // Accessible (protected in base)
        // age = 5;         // ERROR: private in base
        // setAge(5);       // ERROR: private in base
    }
    
    void bark() {
        cout << name << " barks: Woof! Woof!" << endl;
    }
};

// Protected Inheritance
class Cat : protected Animal {
public:
    Cat(string n) {
        name = n;           // Accessible (now protected)
        setSpecies("Cat");  // Accessible (protected)
        // age = 3;         // ERROR: private in base
    }
    
    void meow() {
        cout << name << " meows: Meow!" << endl;
    }
    
    // Provide public interface to access base methods
    void makeSound() {
        speak();  // Can access because it's now protected
    }
};

// Private Inheritance
class Bird : private Animal {
public:
    Bird(string n) {
        name = n;           // Accessible (now private)
        setSpecies("Bird"); // Accessible (now private)
    }
    
    void chirp() {
        cout << name << " chirps: Tweet! Tweet!" << endl;
    }
    
    // Provide public interface
    void makeAnimalSound() {
        speak();  // Can access because it's now private
    }
};

int main() {
    cout << "=== Public Inheritance Example ===" << endl;
    Dog myDog("Buddy");
    myDog.speak();      // Accessible (public inheritance)
    myDog.bark();
    // myDog.species = "Canine";  // ERROR: protected
    
    cout << "\n=== Protected Inheritance Example ===" << endl;
    Cat myCat("Whiskers");
    myCat.meow();
    myCat.makeSound();  // Uses provided interface
    // myCat.speak();    // ERROR: speak() is now protected
    
    cout << "\n=== Private Inheritance Example ===" << endl;
    Bird myBird("Tweety");
    myBird.chirp();
    myBird.makeAnimalSound();  // Uses provided interface
    // myBird.speak();   // ERROR: speak() is now private
    
    return 0;
}
Access Specifier Rules:
  • public: Accessible everywhere
  • protected: Accessible in derived classes
  • private: Accessible only in own class
  • Choose public inheritance for "is-a" relationships
  • Use private inheritance for "implemented-in-terms-of"
Common Mistakes:
  • Forgetting access specifiers
  • Using private inheritance incorrectly
  • Trying to access private base members
  • Not providing interfaces for private/protected inheritance
  • Confusing "has-a" with "is-a" relationships

2. Single Inheritance

Single inheritance is the simplest form where a derived class inherits from only one base class.

Basic Syntax
class Base {
    // Base class members
};

class Derived : access-specifier Base {
    // Derived class members
};
Single Inheritance Examples
#include <iostream>
#include <string>
using namespace std;

// Base class
class Vehicle {
protected:
    string brand;
    int year;
    
public:
    Vehicle(string b, int y) : brand(b), year(y) {
        cout << "Vehicle constructor called." << endl;
    }
    
    void displayInfo() {
        cout << "Brand: " << brand << ", Year: " << year;
    }
    
    void start() {
        cout << brand << " is starting..." << endl;
    }
    
    ~Vehicle() {
        cout << "Vehicle destructor called." << endl;
    }
};

// Derived class using single inheritance
class Car : public Vehicle {
private:
    int doors;
    string fuelType;
    
public:
    // Constructor with initialization list
    Car(string b, int y, int d, string f) 
        : Vehicle(b, y), doors(d), fuelType(f) {
        cout << "Car constructor called." << endl;
    }
    
    // Override base class function
    void displayInfo() {
        Vehicle::displayInfo();  // Call base class method
        cout << ", Doors: " << doors 
             << ", Fuel: " << fuelType << endl;
    }
    
    // New functionality specific to Car
    void honk() {
        cout << brand << " honks: Beep! Beep!" << endl;
    }
    
    // Additional methods
    void refuel() {
        cout << "Refueling " << brand << " with " << fuelType << endl;
    }
    
    ~Car() {
        cout << "Car destructor called." << endl;
    }
};

// Another derived class
class Motorcycle : public Vehicle {
private:
    bool hasHelmet;
    
public:
    Motorcycle(string b, int y, bool helmet) 
        : Vehicle(b, y), hasHelmet(helmet) {
        cout << "Motorcycle constructor called." << endl;
    }
    
    void displayInfo() {
        Vehicle::displayInfo();
        cout << ", Has helmet: " << (hasHelmet ? "Yes" : "No") << endl;
    }
    
    void wheelie() {
        cout << brand << " is doing a wheelie!" << endl;
    }
};

int main() {
    cout << "=== Single Inheritance Demo ===" << endl << endl;
    
    // Create Car object
    cout << "Creating Car object:" << endl;
    Car myCar("Toyota", 2022, 4, "Gasoline");
    myCar.displayInfo();
    myCar.start();
    myCar.honk();
    myCar.refuel();
    
    cout << endl;
    
    // Create Motorcycle object
    cout << "Creating Motorcycle object:" << endl;
    Motorcycle myBike("Harley", 2021, true);
    myBike.displayInfo();
    myBike.start();
    myBike.wheelie();
    
    cout << endl;
    
    // Using base class pointer with derived objects
    cout << "Using base class pointers:" << endl;
    Vehicle* vehicle1 = &myCar;
    Vehicle* vehicle2 = &myBike;
    
    vehicle1->start();
    vehicle2->start();
    
    // vehicle1->honk();  // ERROR: Vehicle doesn't have honk()
    
    return 0;
}

Key Points: Single Inheritance

  • Most common and straightforward inheritance type
  • Establishes clear "is-a" relationship
  • Derived class can override base class methods
  • Constructors called from base to derived
  • Destructors called from derived to base

3. Multiple Inheritance

Multiple inheritance allows a class to inherit from more than one base class, combining their features.

Basic Syntax
class Base1 {
    // First base class
};

class Base2 {
    // Second base class
};

class Derived : public Base1, public Base2 {
    // Inherits from both Base1 and Base2
};
Multiple Inheritance Examples
#include <iostream>
#include <string>
using namespace std;

// First base class
class Printer {
protected:
    string brand;
    int dpi;
    
public:
    Printer(string b, int d) : brand(b), dpi(d) {}
    
    void printInfo() {
        cout << "Printer: " << brand << " (" << dpi << " DPI)" << endl;
    }
    
    virtual void printDocument(string doc) {
        cout << "Printing document: " << doc << endl;
    }
};

// Second base class
class Scanner {
protected:
    string scanType;
    int resolution;
    
public:
    Scanner(string t, int r) : scanType(t), resolution(r) {}
    
    void scanInfo() {
        cout << "Scanner type: " << scanType 
             << " (" << resolution << " DPI)" << endl;
    }
    
    virtual void scanDocument() {
        cout << "Scanning document..." << endl;
    }
};

// Third base class
class Fax {
protected:
    string faxNumber;
    
public:
    Fax(string num) : faxNumber(num) {}
    
    void faxInfo() {
        cout << "Fax number: " << faxNumber << endl;
    }
    
    virtual void sendFax(string doc) {
        cout << "Sending fax: " << doc 
             << " to " << faxNumber << endl;
    }
};

// Derived class with multiple inheritance
class MultifunctionPrinter : public Printer, public Scanner, public Fax {
private:
    bool isColor;
    
public:
    MultifunctionPrinter(string b, int dpi, string scanT, 
                        int res, string faxNum, bool color)
        : Printer(b, dpi), Scanner(scanT, res), 
          Fax(faxNum), isColor(color) {}
    
    // Override methods
    void printDocument(string doc) override {
        cout << "MFP printing: " << doc;
        if (isColor) cout << " in COLOR";
        cout << endl;
    }
    
    void scanDocument() override {
        cout << "MFP scanning at " << resolution << " DPI" << endl;
    }
    
    // New functionality
    void copyDocument(string doc) {
        cout << "Copying document: " << doc << endl;
        scanDocument();  // Simulate scanning
        printDocument(doc);  // Simulate printing
    }
    
    void displayAllInfo() {
        printInfo();
        scanInfo();
        faxInfo();
        cout << "Color capable: " << (isColor ? "Yes" : "No") << endl;
    }
};

// Another example: Student and Employee
class Student {
protected:
    string studentId;
    float gpa;
    
public:
    Student(string id, float g) : studentId(id), gpa(g) {}
    
    void study() {
        cout << "Student " << studentId << " is studying." << endl;
    }
    
    void displayStudentInfo() {
        cout << "Student ID: " << studentId 
             << ", GPA: " << gpa << endl;
    }
};

class Employee {
protected:
    string employeeId;
    float salary;
    
public:
    Employee(string id, float s) : employeeId(id), salary(s) {}
    
    void work() {
        cout << "Employee " << employeeId << " is working." << endl;
    }
    
    void displayEmployeeInfo() {
        cout << "Employee ID: " << employeeId 
             << ", Salary: $" << salary << endl;
    }
};

// StudentEmployee inherits from both Student and Employee
class StudentEmployee : public Student, public Employee {
private:
    int hoursPerWeek;
    
public:
    StudentEmployee(string sid, float g, string eid, 
                   float s, int hours)
        : Student(sid, g), Employee(eid, s), 
          hoursPerWeek(hours) {}
    
    void displayInfo() {
        displayStudentInfo();
        displayEmployeeInfo();
        cout << "Hours per week: " << hoursPerWeek << endl;
    }
    
    void manageSchedule() {
        cout << "Managing schedule as student and employee." << endl;
        study();
        work();
    }
};

int main() {
    cout << "=== Multiple Inheritance Demo ===" << endl << endl;
    
    // Multifunction printer example
    cout << "1. Multifunction Printer:" << endl;
    MultifunctionPrinter mfp("HP", 1200, "Flatbed", 
                            600, "555-1234", true);
    mfp.displayAllInfo();
    mfp.printDocument("Report.pdf");
    mfp.scanDocument();
    mfp.sendFax("Contract.docx");
    mfp.copyDocument("Notes.txt");
    
    cout << endl;
    
    // StudentEmployee example
    cout << "2. Student Employee:" << endl;
    StudentEmployee intern("S12345", 3.8, "E9876", 
                          2000.0, 20);
    intern.displayInfo();
    intern.manageSchedule();
    
    return 0;
}
Advantages
  • Combine features from multiple classes
  • Greater code reuse
  • Flexible class design
  • Model complex real-world relationships
Disadvantages
  • Diamond problem (ambiguous inheritance)
  • Increased complexity
  • Constructor order complications
  • Harder to maintain

4. Multilevel Inheritance

Multilevel inheritance involves a chain of inheritance where a class is derived from another derived class.

Basic Syntax
class Grandparent {
    // Base class
};

class Parent : public Grandparent {
    // Intermediate class
};

class Child : public Parent {
    // Most derived class
};
Multilevel Inheritance Examples
#include <iostream>
#include <string>
using namespace std;

// Level 1: Base class
class Animal {
protected:
    string species;
    int age;
    
public:
    Animal(string s, int a) : species(s), age(a) {
        cout << "Animal constructor: " << species << endl;
    }
    
    void breathe() {
        cout << species << " is breathing." << endl;
    }
    
    void eat(string food) {
        cout << species << " is eating " << food << "." << endl;
    }
    
    void displayInfo() {
        cout << "Species: " << species 
             << ", Age: " << age << " years" << endl;
    }
    
    virtual ~Animal() {
        cout << "Animal destructor: " << species << endl;
    }
};

// Level 2: Intermediate class
class Mammal : public Animal {
protected:
    bool hasFur;
    string furColor;
    
public:
    Mammal(string s, int a, bool fur, string color) 
        : Animal(s, a), hasFur(fur), furColor(color) {
        cout << "Mammal constructor: " << species << endl;
    }
    
    void nurseYoung() {
        cout << species << " is nursing its young." << endl;
    }
    
    void displayInfo() {
        Animal::displayInfo();
        cout << "Has fur: " << (hasFur ? "Yes" : "No");
        if (hasFur) cout << ", Color: " << furColor;
        cout << endl;
    }
    
    ~Mammal() {
        cout << "Mammal destructor: " << species << endl;
    }
};

// Level 3: Further derived class
class Dog : public Mammal {
private:
    string breed;
    string barkSound;
    
public:
    Dog(string s, int a, bool fur, string color, 
        string b, string sound) 
        : Mammal(s, a, fur, color), breed(b), barkSound(sound) {
        cout << "Dog constructor: " << species << endl;
    }
    
    void bark() {
        cout << species << " barks: " << barkSound << endl;
    }
    
    void fetch(string item) {
        cout << species << " is fetching " << item << "." << endl;
    }
    
    void displayInfo() {
        Mammal::displayInfo();
        cout << "Breed: " << breed << endl;
    }
    
    // Override eat method
    void eat(string food) override {
        if (food == "chocolate") {
            cout << species << " cannot eat chocolate! It's toxic!" << endl;
        } else {
            Animal::eat(food);
        }
    }
    
    ~Dog() {
        cout << "Dog destructor: " << species << endl;
    }
};

// Another level: Specialized dog
class ServiceDog : public Dog {
private:
    string serviceType;
    string handlerName;
    
public:
    ServiceDog(string s, int a, bool fur, string color,
               string b, string sound, string service, string handler)
        : Dog(s, a, fur, color, b, sound), 
          serviceType(service), handlerName(handler) {
        cout << "ServiceDog constructor: " << species << endl;
    }
    
    void performService() {
        cout << species << " is performing " 
             << serviceType << " service." << endl;
    }
    
    void displayInfo() {
        Dog::displayInfo();
        cout << "Service type: " << serviceType 
             << ", Handler: " << handlerName << endl;
    }
    
    ~ServiceDog() {
        cout << "ServiceDog destructor: " << species << endl;
    }
};

// Different branch of multilevel inheritance
class Bird : public Animal {
protected:
    double wingspan;
    bool canFly;
    
public:
    Bird(string s, int a, double ws, bool fly) 
        : Animal(s, a), wingspan(ws), canFly(fly) {
        cout << "Bird constructor: " << species << endl;
    }
    
    void fly() {
        if (canFly) {
            cout << species << " is flying with " 
                 << wingspan << "m wingspan." << endl;
        } else {
            cout << species << " cannot fly." << endl;
        }
    }
    
    void displayInfo() {
        Animal::displayInfo();
        cout << "Wingspan: " << wingspan 
             << "m, Can fly: " << (canFly ? "Yes" : "No") << endl;
    }
};

class Parrot : public Bird {
private:
    string vocabulary;
    
public:
    Parrot(string s, int a, double ws, bool fly, string vocab) 
        : Bird(s, a, ws, fly), vocabulary(vocab) {
        cout << "Parrot constructor: " << species << endl;
    }
    
    void talk() {
        cout << species << " says: \"" << vocabulary << "\"" << endl;
    }
};

int main() {
    cout << "=== Multilevel Inheritance Demo ===" << endl << endl;
    
    cout << "1. Dog (Animal -> Mammal -> Dog):" << endl;
    Dog myDog("Canine", 5, true, "Brown", 
             "Golden Retriever", "Woof! Woof!");
    myDog.displayInfo();
    myDog.breathe();
    myDog.eat("dog food");
    myDog.eat("chocolate");  // Overridden method
    myDog.nurseYoung();      // From Mammal
    myDog.bark();
    myDog.fetch("ball");
    
    cout << endl;
    
    cout << "2. ServiceDog (Animal -> Mammal -> Dog -> ServiceDog):" << endl;
    ServiceDog serviceDog("Canine", 4, true, "Black",
                         "Labrador", "Woof!", 
                         "guide", "John");
    serviceDog.displayInfo();
    serviceDog.performService();
    
    cout << endl;
    
    cout << "3. Parrot (Animal -> Bird -> Parrot):" << endl;
    Parrot myParrot("Parrot", 2, 0.5, true, 
                   "Hello! Pretty bird!");
    myParrot.displayInfo();
    myParrot.fly();
    myParrot.talk();
    
    cout << endl;
    cout << "Destructors will be called in reverse order..." << endl;
    
    return 0;
}
Constructor/Destructor Order in Multilevel Inheritance:
  • Constructors: Base → Intermediate → Derived (top to bottom)
  • Destructors: Derived → Intermediate → Base (bottom to top)
  • Each constructor initializes its own members first
  • Virtual destructors ensure proper cleanup
  • Use initialization lists for efficiency

5. Hierarchical Inheritance

Hierarchical inheritance involves multiple derived classes inheriting from a single base class.

Hierarchical Inheritance Examples
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// Base class: Shape
class Shape {
protected:
    string name;
    string color;
    
public:
    Shape(string n, string c) : name(n), color(c) {}
    
    virtual double area() = 0;  // Pure virtual function
    virtual double perimeter() = 0;  // Pure virtual function
    
    void displayInfo() {
        cout << name << " (" << color << ")" << endl;
        cout << "Area: " << area() << ", Perimeter: " 
             << perimeter() << endl;
    }
    
    virtual void draw() {
        cout << "Drawing " << name << " in " << color << " color." << endl;
    }
    
    virtual ~Shape() {
        cout << "Shape destructor: " << name << endl;
    }
};

// Derived class 1: Circle
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(string n, string c, double r) 
        : Shape(n, c), radius(r) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() override {
        return 2 * 3.14159 * radius;
    }
    
    void draw() override {
        Shape::draw();
        cout << "  Drawing circle with radius " << radius << endl;
    }
    
    // Circle-specific method
    double diameter() {
        return 2 * radius;
    }
};

// Derived class 2: Rectangle
class Rectangle : public Shape {
private:
    double length;
    double width;
    
public:
    Rectangle(string n, string c, double l, double w) 
        : Shape(n, c), length(l), width(w) {}
    
    double area() override {
        return length * width;
    }
    
    double perimeter() override {
        return 2 * (length + width);
    }
    
    void draw() override {
        Shape::draw();
        cout << "  Drawing rectangle " << length 
             << " x " << width << endl;
    }
    
    // Rectangle-specific method
    bool isSquare() {
        return length == width;
    }
};

// Derived class 3: Triangle
class Triangle : public Shape {
private:
    double base;
    double height;
    double side1, side2, side3;
    
public:
    Triangle(string n, string c, double b, double h, 
            double s1, double s2, double s3)
        : Shape(n, c), base(b), height(h), 
          side1(s1), side2(s2), side3(s3) {}
    
    double area() override {
        return 0.5 * base * height;
    }
    
    double perimeter() override {
        return side1 + side2 + side3;
    }
    
    void draw() override {
        Shape::draw();
        cout << "  Drawing triangle with sides " 
             << side1 << ", " << side2 << ", " << side3 << endl;
    }
    
    // Triangle-specific method
    string triangleType() {
        if (side1 == side2 && side2 == side3) return "Equilateral";
        if (side1 == side2 || side2 == side3 || side1 == side3) return "Isosceles";
        return "Scalene";
    }
};

// Another hierarchical example: Employees
class Employee {
protected:
    string name;
    int id;
    double salary;
    
public:
    Employee(string n, int i, double s) 
        : name(n), id(i), salary(s) {}
    
    virtual void work() {
        cout << name << " is working." << endl;
    }
    
    virtual void displayInfo() {
        cout << "ID: " << id << ", Name: " << name 
             << ", Salary: $" << salary << endl;
    }
    
    virtual double calculateBonus() {
        return 0.0;  // Base implementation
    }
};

class Manager : public Employee {
private:
    string department;
    int teamSize;
    
public:
    Manager(string n, int i, double s, string dept, int team)
        : Employee(n, i, s), department(dept), teamSize(team) {}
    
    void work() override {
        cout << name << " is managing " << department 
             << " department." << endl;
    }
    
    void displayInfo() override {
        Employee::displayInfo();
        cout << "  Department: " << department 
             << ", Team size: " << teamSize << endl;
    }
    
    double calculateBonus() override {
        return salary * 0.20 + teamSize * 100;
    }
    
    void conductMeeting() {
        cout << name << " is conducting a team meeting." << endl;
    }
};

class Developer : public Employee {
private:
    string programmingLanguage;
    int yearsExperience;
    
public:
    Developer(string n, int i, double s, string lang, int exp)
        : Employee(n, i, s), programmingLanguage(lang), 
          yearsExperience(exp) {}
    
    void work() override {
        cout << name << " is coding in " 
             << programmingLanguage << "." << endl;
    }
    
    void displayInfo() override {
        Employee::displayInfo();
        cout << "  Language: " << programmingLanguage 
             << ", Experience: " << yearsExperience 
             << " years" << endl;
    }
    
    double calculateBonus() override {
        return salary * 0.15 + yearsExperience * 500;
    }
    
    void debugCode() {
        cout << name << " is debugging code." << endl;
    }
};

class SalesPerson : public Employee {
private:
    double commissionRate;
    double salesAmount;
    
public:
    SalesPerson(string n, int i, double s, double rate, double sales)
        : Employee(n, i, s), commissionRate(rate), 
          salesAmount(sales) {}
    
    void work() override {
        cout << name << " is making sales calls." << endl;
    }
    
    void displayInfo() override {
        Employee::displayInfo();
        cout << "  Commission: " << (commissionRate * 100) 
             << "%, Sales: $" << salesAmount << endl;
    }
    
    double calculateBonus() override {
        return salesAmount * commissionRate;
    }
    
    void makeSale(double amount) {
        salesAmount += amount;
        cout << name << " made a sale of $" << amount << "!" << endl;
    }
};

int main() {
    cout << "=== Hierarchical Inheritance Demo ===" << endl << endl;
    
    cout << "1. Shapes (Base: Shape):" << endl;
    Circle circle("Circle", "Red", 5.0);
    Rectangle rectangle("Rectangle", "Blue", 4.0, 6.0);
    Triangle triangle("Triangle", "Green", 3.0, 4.0, 3.0, 4.0, 5.0);
    
    circle.displayInfo();
    circle.draw();
    cout << "Diameter: " << circle.diameter() << endl << endl;
    
    rectangle.displayInfo();
    rectangle.draw();
    cout << "Is square? " << (rectangle.isSquare() ? "Yes" : "No") 
         << endl << endl;
    
    triangle.displayInfo();
    triangle.draw();
    cout << "Triangle type: " << triangle.triangleType() 
         << endl << endl;
    
    cout << "2. Employees (Base: Employee):" << endl;
    Manager manager("Alice", 101, 80000, "Engineering", 10);
    Developer developer("Bob", 102, 70000, "C++", 5);
    SalesPerson salesperson("Charlie", 103, 50000, 0.10, 100000);
    
    manager.displayInfo();
    manager.work();
    manager.conductMeeting();
    cout << "Bonus: $" << manager.calculateBonus() << endl << endl;
    
    developer.displayInfo();
    developer.work();
    developer.debugCode();
    cout << "Bonus: $" << developer.calculateBonus() << endl << endl;
    
    salesperson.displayInfo();
    salesperson.work();
    salesperson.makeSale(5000);
    cout << "Bonus: $" << salesperson.calculateBonus() << endl;
    
    return 0;
}
When to Use Hierarchical Inheritance:
  • When you have a general category with specific subcategories
  • When multiple classes share common functionality
  • For implementing polymorphism through base class pointers
  • When creating class libraries or frameworks
  • For database entity relationships

6. Virtual Functions and Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common base class. Virtual functions enable runtime polymorphism.

Virtual Function

Function that can be overridden in derived classes.

class Base {
public:
    virtual void show() {
        cout << "Base show";
    }
};

class Derived : public Base {
public:
    void show() override {
        cout << "Derived show";
    }
};
Pure Virtual Function

Makes class abstract (cannot be instantiated).

class Abstract {
public:
    virtual void pure() = 0;
};

class Concrete : public Abstract {
public:
    void pure() override {
        // Implementation
    }
};
Virtual Destructor

Ensures proper cleanup of derived objects.

class Base {
public:
    virtual ~Base() {
        // Cleanup
    }
};

class Derived : public Base {
public:
    ~Derived() override {
        // Derived cleanup
    }
};
Polymorphism Examples
#include <iostream>
#include <vector>
#include <memory>
using namespace std;

// Abstract base class with pure virtual function
class Animal {
protected:
    string name;
    
public:
    Animal(string n) : name(n) {}
    
    // Pure virtual function - makes class abstract
    virtual void makeSound() = 0;
    
    // Virtual function with implementation
    virtual void move() {
        cout << name << " is moving." << endl;
    }
    
    // Non-virtual function
    void eat(string food) {
        cout << name << " is eating " << food << "." << endl;
    }
    
    // Virtual destructor
    virtual ~Animal() {
        cout << "Animal destructor: " << name << endl;
    }
};

// Derived classes implementing pure virtual function
class Dog : public Animal {
public:
    Dog(string n) : Animal(n) {}
    
    void makeSound() override {
        cout << name << " says: Woof! Woof!" << endl;
    }
    
    void move() override {
        cout << name << " is running on four legs." << endl;
    }
    
    // Dog-specific method
    void fetch() {
        cout << name << " is fetching the ball." << endl;
    }
    
    ~Dog() override {
        cout << "Dog destructor: " << name << endl;
    }
};

class Cat : public Animal {
public:
    Cat(string n) : Animal(n) {}
    
    void makeSound() override {
        cout << name << " says: Meow! Meow!" << endl;
    }
    
    void move() override {
        cout << name << " is walking gracefully." << endl;
    }
    
    // Cat-specific method
    void climb() {
        cout << name << " is climbing the tree." << endl;
    }
    
    ~Cat() override {
        cout << "Cat destructor: " << name << endl;
    }
};

class Bird : public Animal {
public:
    Bird(string n) : Animal(n) {}
    
    void makeSound() override {
        cout << name << " says: Tweet! Tweet!" << endl;
    }
    
    void move() override {
        cout << name << " is flying in the sky." << endl;
    }
    
    // Bird-specific method
    void buildNest() {
        cout << name << " is building a nest." << endl;
    }
    
    ~Bird() override {
        cout << "Bird destructor: " << name << endl;
    }
};

// Function demonstrating polymorphism
void animalShow(Animal* animal) {
    animal->makeSound();
    animal->move();
    animal->eat("food");
    cout << endl;
}

int main() {
    cout << "=== Polymorphism Demo ===" << endl << endl;
    
    // Create objects of derived classes
    Dog dog("Buddy");
    Cat cat("Whiskers");
    Bird bird("Tweety");
    
    // Using base class pointers with derived objects
    Animal* animal1 = &dog;
    Animal* animal2 = &cat;
    Animal* animal3 = &bird;
    
    cout << "1. Using base class pointers:" << endl;
    animal1->makeSound();  // Calls Dog::makeSound()
    animal2->makeSound();  // Calls Cat::makeSound()
    animal3->makeSound();  // Calls Bird::makeSound()
    
    cout << endl << "2. Function with polymorphism:" << endl;
    animalShow(&dog);
    animalShow(&cat);
    animalShow(&bird);
    
    cout << "3. Array/Vector of base class pointers:" << endl;
    vector<Animal*> zoo;
    zoo.push_back(new Dog("Rex"));
    zoo.push_back(new Cat("Mittens"));
    zoo.push_back(new Bird("Polly"));
    zoo.push_back(new Dog("Max"));
    
    for (Animal* animal : zoo) {
        animal->makeSound();
    }
    
    cout << endl << "4. Dynamic casting to access derived methods:" << endl;
    for (Animal* animal : zoo) {
        if (Dog* dogPtr = dynamic_cast<Dog*>(animal)) {
            dogPtr->fetch();
        } else if (Cat* catPtr = dynamic_cast<Cat*>(animal)) {
            catPtr->climb();
        } else if (Bird* birdPtr = dynamic_cast<Bird*>(animal)) {
            birdPtr->buildNest();
        }
    }
    
    cout << endl << "5. Smart pointers with polymorphism:" << endl;
    vector<unique_ptr<Animal>> smartZoo;
    smartZoo.push_back(make_unique<Dog>("SmartRex"));
    smartZoo.push_back(make_unique<Cat>("SmartMittens"));
    smartZoo.push_back(make_unique<Bird>("SmartPolly"));
    
    for (auto& animal : smartZoo) {
        animal->makeSound();
    }
    
    // Cleanup for raw pointers
    for (Animal* animal : zoo) {
        delete animal;
    }
    zoo.clear();
    
    cout << endl << "Destructors called automatically..." << endl;
    
    return 0;
}
Important Rules for Virtual Functions:
  • Always declare destructor as virtual in base classes
  • Use override keyword (C++11) for clarity
  • Virtual functions have runtime overhead
  • Constructors cannot be virtual
  • Static functions cannot be virtual
  • Use final keyword (C++11) to prevent further overriding

7. Diamond Problem and Virtual Inheritance

The diamond problem occurs in multiple inheritance when a class inherits from two classes that both inherit from the same base class. Virtual inheritance solves this.

Diamond Problem and Solution
#include <iostream>
using namespace std;

// Base class
class Animal {
protected:
    string species;
    int age;
    
public:
    Animal(string s, int a) : species(s), age(a) {
        cout << "Animal constructor called." << endl;
    }
    
    void breathe() {
        cout << species << " is breathing." << endl;
    }
    
    virtual ~Animal() {
        cout << "Animal destructor called." << endl;
    }
};

// WITHOUT virtual inheritance - PROBLEM
class Mammal : public Animal {
public:
    Mammal(string s, int a) : Animal(s, a) {
        cout << "Mammal constructor called." << endl;
    }
    
    void nurse() {
        cout << species << " is nursing young." << endl;
    }
};

class WingedAnimal : public Animal {
public:
    WingedAnimal(string s, int a) : Animal(s, a) {
        cout << "WingedAnimal constructor called." << endl;
    }
    
    void fly() {
        cout << species << " is flying." << endl;
    }
};

// Bat inherits from both Mammal and WingedAnimal
// PROBLEM: Two copies of Animal base class
class BatProblem : public Mammal, public WingedAnimal {
public:
    BatProblem(string s, int a) 
        : Mammal(s, a), WingedAnimal(s, a) {
        cout << "BatProblem constructor called." << endl;
    }
    
    void display() {
        // ERROR: Ambiguous - which species?
        // cout << "Species: " << species << endl;
        
        // Need to specify which base class
        cout << "Mammal species: " << Mammal::species << endl;
        cout << "WingedAnimal species: " << WingedAnimal::species << endl;
    }
};

// WITH virtual inheritance - SOLUTION
class VirtualMammal : virtual public Animal {
public:
    VirtualMammal(string s, int a) : Animal(s, a) {
        cout << "VirtualMammal constructor called." << endl;
    }
    
    void nurse() {
        cout << species << " is nursing young." << endl;
    }
};

class VirtualWingedAnimal : virtual public Animal {
public:
    VirtualWingedAnimal(string s, int a) : Animal(s, a) {
        cout << "VirtualWingedAnimal constructor called." << endl;
    }
    
    void fly() {
        cout << species << " is flying." << endl;
    }
};

// BatSolution inherits from both virtual base classes
class BatSolution : public VirtualMammal, public VirtualWingedAnimal {
public:
    // Animal constructor called directly by most derived class
    BatSolution(string s, int a) 
        : Animal(s, a), VirtualMammal(s, a), VirtualWingedAnimal(s, a) {
        cout << "BatSolution constructor called." << endl;
    }
    
    void display() {
        // NO AMBIGUITY: Only one copy of Animal
        cout << "Species: " << species << ", Age: " << age << endl;
    }
    
    void batBehavior() {
        cout << species << " is using echolocation." << endl;
        nurse();  // From VirtualMammal
        fly();    // From VirtualWingedAnimal
    }
};

// Another practical example: Teaching Assistant
class Person {
protected:
    string name;
    int id;
    
public:
    Person(string n, int i) : name(n), id(i) {
        cout << "Person constructor: " << name << endl;
    }
    
    void introduce() {
        cout << "Hi, I'm " << name << " (ID: " << id << ")" << endl;
    }
    
    virtual ~Person() {
        cout << "Person destructor: " << name << endl;
    }
};

// Without virtual inheritance (problem)
class StudentProblem : public Person {
public:
    StudentProblem(string n, int i) : Person(n, i) {
        cout << "StudentProblem constructor." << endl;
    }
    
    void study() {
        cout << name << " is studying." << endl;
    }
};

class TeacherProblem : public Person {
public:
    TeacherProblem(string n, int i) : Person(n, i) {
        cout << "TeacherProblem constructor." << endl;
    }
    
    void teach() {
        cout << name << " is teaching." << endl;
    }
};

// TeachingAssistant inherits from both Student and Teacher
class TeachingAssistantProblem : public StudentProblem, public TeacherProblem {
public:
    TeachingAssistantProblem(string n, int studentId, int teacherId)
        : StudentProblem(n, studentId), TeacherProblem(n, teacherId) {
        cout << "TeachingAssistantProblem constructor." << endl;
    }
    
    void work() {
        // Ambiguous: which name?
        // cout << name << " is working as TA." << endl;
        
        StudentProblem::study();
        TeacherProblem::teach();
    }
};

// With virtual inheritance (solution)
class StudentSolution : virtual public Person {
public:
    StudentSolution(string n, int i) : Person(n, i) {
        cout << "StudentSolution constructor." << endl;
    }
    
    void study() {
        cout << name << " is studying." << endl;
    }
};

class TeacherSolution : virtual public Person {
public:
    TeacherSolution(string n, int i) : Person(n, i) {
        cout << "TeacherSolution constructor." << endl;
    }
    
    void teach() {
        cout << name << " is teaching." << endl;
    }
};

class TeachingAssistantSolution : public StudentSolution, public TeacherSolution {
public:
    TeachingAssistantSolution(string n, int id) 
        : Person(n, id), StudentSolution(n, id), TeacherSolution(n, id) {
        cout << "TeachingAssistantSolution constructor." << endl;
    }
    
    void work() {
        // No ambiguity
        cout << name << " is working as TA." << endl;
        study();
        teach();
    }
};

int main() {
    cout << "=== Diamond Problem and Virtual Inheritance ===" << endl << endl;
    
    cout << "1. PROBLEM: Bat without virtual inheritance" << endl;
    BatProblem batProblem("Bat", 2);
    cout << "Size of BatProblem: " << sizeof(batProblem) 
         << " bytes (has two Animal copies)" << endl;
    batProblem.display();
    // batProblem.breathe();  // ERROR: ambiguous
    batProblem.Mammal::breathe();
    batProblem.WingedAnimal::breathe();
    
    cout << endl;
    
    cout << "2. SOLUTION: Bat with virtual inheritance" << endl;
    BatSolution batSolution("Bat", 3);
    cout << "Size of BatSolution: " << sizeof(batSolution) 
         << " bytes (has one Animal copy)" << endl;
    batSolution.display();
    batSolution.breathe();  // No ambiguity
    batSolution.batBehavior();
    
    cout << endl;
    
    cout << "3. Teaching Assistant Problem" << endl;
    TeachingAssistantProblem taProblem("Alice", 1001, 2001);
    cout << "Size: " << sizeof(taProblem) << " bytes" << endl;
    taProblem.StudentProblem::introduce();  // Need to specify
    taProblem.TeacherProblem::introduce();  // Two different Persons
    taProblem.work();
    
    cout << endl;
    
    cout << "4. Teaching Assistant Solution" << endl;
    TeachingAssistantSolution taSolution("Bob", 3001);
    cout << "Size: " << sizeof(taSolution) << " bytes" << endl;
    taSolution.introduce();  // No ambiguity
    taSolution.work();
    
    cout << endl << "Destructors called in reverse order..." << endl;
    
    return 0;
}
Virtual Inheritance Guidelines:
  • Use virtual inheritance to solve diamond problem
  • Most derived class calls virtual base constructor directly
  • Virtual base constructor called before non-virtual base constructors
  • Adds overhead (virtual base pointer)
  • Use only when diamond inheritance is necessary
  • Consider composition over multiple inheritance

8. Best Practices and Common Mistakes

Best Practices
  • Use public inheritance for "is-a" relationships
  • Prefer composition over multiple inheritance
  • Always make destructors virtual in base classes
  • Use override keyword (C++11) for clarity
  • Keep inheritance hierarchies shallow (2-3 levels)
  • Use abstract base classes for interfaces
  • Document inheritance relationships clearly
Common Mistakes
  • Forgetting virtual destructors
  • Deep inheritance hierarchies
  • Using multiple inheritance unnecessarily
  • Confusing "has-a" with "is-a" relationships
  • Not using access specifiers correctly
  • Circular inheritance dependencies
  • Ignoring the diamond problem
Good vs Bad Inheritance Design
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// BAD DESIGN: Deep hierarchy, improper relationships
class BadVehicle {
    // Too many responsibilities
};

class BadCar : public BadVehicle {
    // ...
};

class BadSportsCar : public BadCar {
    // Too deep
};

class BadConvertible : public BadSportsCar {
    // Even deeper
};

// BAD: Multiple inheritance for wrong reasons
class Engine {
    // ...
};

class Radio {
    // ...
};

class BadCarDesign : public Engine, public Radio {  // WRONG: Car has-an engine, not is-an engine
    // ...
};

// GOOD DESIGN: Proper "is-a" relationships
class GoodVehicle {
protected:
    string make;
    string model;
    int year;
    
public:
    GoodVehicle(string m, string mdl, int y) 
        : make(m), model(mdl), year(y) {}
    
    virtual void start() = 0;  // Pure virtual
    virtual void stop() = 0;   // Pure virtual
    
    virtual ~GoodVehicle() = default;
};

class GoodCar : public GoodVehicle {
protected:
    int doors;
    
public:
    GoodCar(string m, string mdl, int y, int d)
        : GoodVehicle(m, mdl, y), doors(d) {}
    
    void start() override {
        cout << make << " " << model << " car starting." << endl;
    }
    
    void stop() override {
        cout << make << " " << model << " car stopping." << endl;
    }
};

class GoodMotorcycle : public GoodVehicle {
protected:
    bool hasSidecar;
    
public:
    GoodMotorcycle(string m, string mdl, int y, bool sidecar)
        : GoodVehicle(m, mdl, y), hasSidecar(sidecar) {}
    
    void start() override {
        cout << make << " " << model << " motorcycle starting." << endl;
    }
    
    void stop() override {
        cout << make << " " << model << " motorcycle stopping." << endl;
    }
};

// GOOD: Composition over inheritance
class RadioComponent {
private:
    string brand;
    int maxVolume;
    
public:
    RadioComponent(string b, int vol) : brand(b), maxVolume(vol) {}
    
    void turnOn() {
        cout << brand << " radio turned on." << endl;
    }
    
    void setStation(double frequency) {
        cout << "Tuned to " << frequency << " MHz." << endl;
    }
};

class EngineComponent {
private:
    int horsepower;
    string fuelType;
    
public:
    EngineComponent(int hp, string fuel) 
        : horsepower(hp), fuelType(fuel) {}
    
    void ignite() {
        cout << "Engine (" << horsepower 
             << " HP) ignited with " << fuelType << endl;
    }
};

class GoodCarDesign {
private:
    GoodVehicle* vehicle;  // Has-a vehicle (could be any type)
    EngineComponent engine;
    RadioComponent radio;
    
public:
    GoodCarDesign(GoodVehicle* v, int hp, string fuel, string radioBrand)
        : vehicle(v), engine(hp, fuel), radio(radioBrand, 100) {}
    
    void operate() {
        vehicle->start();
        engine.ignite();
        radio.turnOn();
        radio.setStation(98.5);
        vehicle->stop();
    }
    
    ~GoodCarDesign() {
        delete vehicle;
    }
};

// GOOD: Interface inheritance
class IPrintable {
public:
    virtual void print() const = 0;
    virtual ~IPrintable() = default;
};

class IScannable {
public:
    virtual void scan() = 0;
    virtual ~IScannable() = default;
};

class Document : public IPrintable {
private:
    string content;
    
public:
    Document(string c) : content(c) {}
    
    void print() const override {
        cout << "Printing document: " << content << endl;
    }
};

class Photo : public IPrintable, public IScannable {
private:
    string imageData;
    
public:
    Photo(string img) : imageData(img) {}
    
    void print() const override {
        cout << "Printing photo..." << endl;
    }
    
    void scan() override {
        cout << "Scanning photo..." << endl;
    }
};

void printItem(const IPrintable& item) {
    item.print();  // Polymorphic call
}

int main() {
    cout << "=== Good Inheritance Design Examples ===" << endl << endl;
    
    // Good inheritance hierarchy
    GoodCar car("Toyota", "Camry", 2022, 4);
    GoodMotorcycle bike("Harley", "Davidson", 2021, false);
    
    car.start();
    car.stop();
    
    bike.start();
    bike.stop();
    
    cout << endl;
    
    // Composition example
    GoodCarDesign carDesign(new GoodCar("Honda", "Accord", 2023, 4), 
                           200, "gasoline", "Sony");
    carDesign.operate();
    
    cout << endl;
    
    // Interface inheritance
    Document doc("Hello World Document");
    Photo photo("Vacation.jpg");
    
    vector<const IPrintable*> items;
    items.push_back(&doc);
    items.push_back(&photo);
    
    for (const IPrintable* item : items) {
        item->print();
    }
    
    // Dynamic casting to check interface
    if (IScannable* scannable = dynamic_cast<IScannable*>(&photo)) {
        scannable->scan();
    }
    
    return 0;
}