Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Polymorphism in C++

Tech 3

Polymorphism enables objects of different classes to be treated as objects of a common base class, allowing the same function call to produce different behaviors depending on the object type. For example, consider a ticket purchasing system where a regular person pays full price, a student pays half price, and a soldier gets priority service.

Conditions for Polymorphism

Polymorphism requires inheritance and two key conditions:

  1. Virtual functions must be called through base class pointers or references.
  2. Derived classes must override the base class virtual functions.
class Customer {
public:
    virtual void purchaseTicket() { std::cout << "Full price ticket" << std::endl; }
};

class StudentCustomer : public Customer {
public:
    virtual void purchaseTicket() override { std::cout << "Half price ticket" << std::endl; }
};

void processPurchase(Customer& cust) {
    cust.purchaseTicket();
}

int main() {
    Customer regular;
    StudentCustomer student;
    processPurchase(regular);
    processPurchase(student);
    return 0;
}

Virtual Functions and Overriding

Virtual functions are declared with the virtual keyword. Overriding occurs when a derived class provides its own implementation of a base class virtual function with identical signature.

class Base {
public:
    virtual void performAction() { std::cout << "Base action" << std::endl; }
};

class Derived : public Base {
public:
    virtual void performAction() override { std::cout << "Derived action" << std::endl; }
};

Exceptions in Overriding

  1. Covariant Return Types: When overriding, the return type can differ if it's a pointer or reference to the class type.
class Shape {};
class Circle : public Shape {};

class ShapeFactory {
public:
    virtual Shape* create() { return new Shape; }
};

class CircleFactory : public ShapeFactory {
public:
    virtual Circle* create() override { return new Circle; }
};
  1. Destructor Overriding: Base class destructors should be virtual to ensure proper cleanup of derived objects.
class Resource {
public:
    virtual ~Resource() { std::cout << "Resource cleanup" << std::endl; }
};

class FileResource : public Resource {
public:
    ~FileResource() override { std::cout << "FileResource cleanup" << std::endl; }
};

C++11 Override and Final Keywords

C++11 introduced override and final to improve code safety:

  • override ensures the function actually overrides a base class virtual function.
  • final prevents further overriding of virtual functions or inheritance of classes.
class Vehicle {
public:
    virtual void startEngine() {}
};

class Car : public Vehicle {
public:
    virtual void startEngine() override { std::cout << "Car engine started" << std::endl; }
};

class SportsCar final : public Car {
public:
    virtual void startEngine() override final { std::cout << "Sports car engine started" << std::endl; }
};

Abstract Classes and Pure Virtual Functions

Abstract classes contain atleast one pure virtual function (declared with = 0). They cannot be instantiated directly and serve as interfaces that derived classes must implement.

class PaymentProcessor {
public:
    virtual void processPayment(double amount) = 0;
};

class CreditCardProcessor : public PaymentProcessor {
public:
    virtual void processPayment(double amount) override {
        std::cout << "Processing credit card payment: $" << amount << std::endl;
    }
};

class PayPalProcessor : public PaymentProcessor {
public:
    virtual void processPayment(double amount) override {
        std::cout << "Processing PayPal payment: $" << amount << std::endl;
    }
};

Interface vs Implementation Inheritance

  • Implementation Inheritance: Derived classes inherit and can use base class function implementations.
  • Interface Inheritance: Derived classes inherit only the function signatures and must provide their own implementations, enabling polymorphism.

Use virtual functions specifically when polymorphism is required; otherwise, regular functions are sufficient.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.