Polymorphism in C++

Hello there, aspiring programmers! Today, we're going to embark on an exciting journey into the world of C++ polymorphism. Don't worry if that word sounds intimidating – by the end of this lesson, you'll be as comfortable with polymorphism as you are with your favorite sneakers!

C++ Polymorphism

What is Polymorphism?

Before we dive into the code, let's understand what polymorphism actually means. The word comes from Greek: 'poly' meaning many, and 'morph' meaning form. In programming, polymorphism allows objects of different types to be treated as objects of a common base type. It's like having a universal remote that can control various devices – pretty cool, right?

Real-world Analogy

Imagine you're at a zoo. You see different animals – lions, elephants, penguins. They're all animals, but they behave differently. When it's feeding time, the zookeeper doesn't need to know exactly what type of animal each one is. They just call a general "eat" command, and each animal responds in its own way. That's polymorphism in action!

Virtual Functions

Now, let's get into the nitty-gritty of C++ polymorphism, starting with virtual functions.

What are Virtual Functions?

Virtual functions are special functions in C++ that allow a program to decide which function to call at runtime based on the type of object being referred to, rather than the type of pointer or reference used.

Here's a simple example:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void makeSound() {
        cout << "The animal makes a sound" << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        cout << "The dog barks: Woof!" << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        cout << "The cat meows: Meow!" << endl;
    }
};

int main() {
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();

    animal1->makeSound();  // Output: The dog barks: Woof!
    animal2->makeSound();  // Output: The cat meows: Meow!

    delete animal1;
    delete animal2;
    return 0;
}

Let's break this down:

  1. We have a base class Animal with a virtual function makeSound().
  2. We create two derived classes, Dog and Cat, each overriding the makeSound() function.
  3. In main(), we create pointers of type Animal* but assign them objects of Dog and Cat.
  4. When we call makeSound(), the program knows to call the correct version based on the actual object type, not the pointer type.

This is the magic of virtual functions and polymorphism!

The 'virtual' Keyword

The virtual keyword is crucial here. It tells the compiler that this function might be overridden in derived classes. Without it, the program would always call the base class version of the function.

Pure Virtual Functions

Now, let's level up and talk about pure virtual functions.

What are Pure Virtual Functions?

A pure virtual function is a virtual function that has no implementation in the base class. It's declared by assigning 0 to the function declaration.

Here's an example:

#include <iostream>
using namespace std;

class Shape {
public:
    virtual double area() = 0;  // Pure virtual function
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double length, width;
public:
    Rectangle(double l, double w) : length(l), width(w) {}
    double area() override {
        return length * width;
    }
};

int main() {
    Shape* shape1 = new Circle(5);
    Shape* shape2 = new Rectangle(4, 5);

    cout << "Circle area: " << shape1->area() << endl;
    cout << "Rectangle area: " << shape2->area() << endl;

    delete shape1;
    delete shape2;
    return 0;
}

In this example:

  1. Shape is an abstract base class with a pure virtual function area().
  2. Circle and Rectangle are concrete classes that inherit from Shape and provide their own implementations of area().
  3. We can create Shape pointers and assign them Circle and Rectangle objects.
  4. When we call area(), the correct version is called based on the actual object type.

Abstract Classes

A class with at least one pure virtual function is called an abstract class. You cannot create objects of an abstract class, but you can use pointers and references to abstract class types.

Why Use Polymorphism?

  1. Flexibility: It allows you to write code that can work with objects of multiple types.
  2. Extensibility: You can add new derived classes without changing the existing code.
  3. Simplicity: It can simplify code by allowing you to treat different objects uniformly.

Common Methods in Polymorphism

Here's a table of common methods used in C++ polymorphism:

Method Description
virtual Keyword used to declare a virtual function in a base class
override Keyword used in derived classes to indicate that a function is overriding a base class function
= 0 Used to declare a pure virtual function
dynamic_cast Used for safe downcasting in polymorphic class hierarchies
typeid Used to get type information at runtime

Conclusion

Polymorphism is a powerful feature in C++ that allows for flexible and extensible code. By using virtual functions and pure virtual functions, you can create hierarchies of classes that can be used interchangeably, leading to more modular and maintainable code.

Remember, like learning any new skill, mastering polymorphism takes practice. Don't be discouraged if it doesn't click immediately – keep coding, keep experimenting, and soon you'll be polymorphing like a pro!

Credits: Image by storyset