C++ Pure Virtual Functions

Introduction

Pure virtual functions in C++ are a key concept in achieving runtime polymorphism and defining abstract classes. A pure virtual function is a virtual function that has no implementation in the base class and must be overridden by derived classes. A class that contains at least one pure virtual function is considered an abstract class and cannot be instantiated directly.

Defining Pure Virtual Functions

To define a pure virtual function, you use the virtual keyword followed by = 0 in the base class. This indicates that the function is pure virtual and must be implemented by any derived class.

Syntax

class Base {
public:
    virtual void pureVirtualFunction() = 0;
};

Example: Pure Virtual Functions and Abstract Classes

Let’s create an example with a base class Shape that contains a pure virtual function draw. Derived classes Circle and Rectangle will provide their own implementations of the draw function.

Code Example

#include <iostream>
using namespace std;

// Abstract base class
class Shape {
public:
    // Pure virtual function
    virtual void draw() = 0;
};

// Derived class inheriting from Shape
class Circle : public Shape {
public:
    // Override the pure virtual function
    void draw() override {
        cout << "Drawing Circle" << endl;
    }
};

// Derived class inheriting from Shape
class Rectangle : public Shape {
public:
    // Override the pure virtual function
    void draw() override {
        cout << "Drawing Rectangle" << endl;
    }
};

int main() {
    // Create objects of derived classes
    Circle circle;
    Rectangle rectangle;

    // Create pointers of base class type
    Shape* shape1 = &circle;
    Shape* shape2 = &rectangle;

    // Call the virtual function
    shape1->draw(); // Calls Circle's draw
    shape2->draw(); // Calls Rectangle's draw

    return 0;
}

Output

Drawing Circle
Drawing Rectangle

Explanation

  • The Shape class is an abstract class with a pure virtual function draw.
  • The Circle and Rectangle classes inherit from Shape and provide their own implementations of the draw function.
  • The main function creates objects of Circle and Rectangle, uses base class pointers to point to these objects, and calls the draw function, demonstrating runtime polymorphism.

Practical Examples

Example 1: Animal Sound Hierarchy

Let’s create a base class Animal with a pure virtual function makeSound. Derived classes Dog and Cat will provide their own implementations of the makeSound function.

#include <iostream>
using namespace std;

// Abstract base class
class Animal {
public:
    // Pure virtual function
    virtual void makeSound() = 0;
};

// Derived class inheriting from Animal
class Dog : public Animal {
public:
    // Override the pure virtual function
    void makeSound() override {
        cout << "Woof Woof" << endl;
    }
};

// Derived class inheriting from Animal
class Cat : public Animal {
public:
    // Override the pure virtual function
    void makeSound() override {
        cout << "Meow Meow" << endl;
    }
};

int main() {
    // Create objects of derived classes
    Dog dog;
    Cat cat;

    // Create pointers of base class type
    Animal* animal1 = &dog;
    Animal* animal2 = &cat;

    // Call the virtual function
    animal1->makeSound(); // Calls Dog's makeSound
    animal2->makeSound(); // Calls Cat's makeSound

    return 0;
}

Output

Woof Woof
Meow Meow

Explanation

  • The Animal class is an abstract base class with a pure virtual function makeSound.
  • The Dog and Cat classes inherit from Animal and provide their own implementations of the makeSound function.
  • The main function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respective makeSound functions.

Example 2: Payment System Hierarchy

Let’s create a base class Payment with a pure virtual function processPayment. Derived classes CreditCardPayment and PayPalPayment will provide their own implementations of the processPayment function.

#include <iostream>
using namespace std;

// Abstract base class
class Payment {
public:
    // Pure virtual function
    virtual void processPayment(double amount) = 0;
};

// Derived class inheriting from Payment
class CreditCardPayment : public Payment {
public:
    // Override the pure virtual function
    void processPayment(double amount) override {
        cout << "Processing credit card payment of $" << amount << endl;
    }
};

// Derived class inheriting from Payment
class PayPalPayment : public Payment {
public:
    // Override the pure virtual function
    void processPayment(double amount) override {
        cout << "Processing PayPal payment of $" << amount << endl;
    }
};

int main() {
    // Create objects of derived classes
    CreditCardPayment ccPayment;
    PayPalPayment ppPayment;

    // Create pointers of base class type
    Payment* payment1 = &ccPayment;
    Payment* payment2 = &ppPayment;

    // Call the virtual function
    payment1->processPayment(100.0); // Calls CreditCardPayment's processPayment
    payment2->processPayment(200.0); // Calls PayPalPayment's processPayment

    return 0;
}

Output

Processing credit card payment of $100
Processing PayPal payment of $200

Explanation

  • The Payment class is an abstract base class with a pure virtual function processPayment.
  • The CreditCardPayment and PayPalPayment classes inherit from Payment and provide their own implementations of the processPayment function.
  • The main function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respective processPayment functions.

Guidelines for Using Pure Virtual Functions

  1. Define Abstract Base Classes: Use pure virtual functions to define abstract base classes that serve as interfaces for derived classes.
  2. Ensure Derived Classes Implement Functions: Derived classes must provide implementations for all pure virtual functions; otherwise, they will also be abstract and cannot be instantiated.
  3. Use for Runtime Polymorphism: Pure virtual functions enable runtime polymorphism, allowing you to write flexible and reusable code.

Example: Abstract Base Class for Shapes

#include <iostream>
using namespace std;

// Abstract base class
class Shape {
public:
    // Pure virtual function for drawing the shape
    virtual void draw() = 0;

    // Pure virtual function for calculating the area
    virtual double area() = 0;
};

// Derived class inheriting from Shape
class Circle : public Shape {
private:
    double radius;

public:
    // Constructor
    Circle(double r) : radius(r) {}

    // Override the pure virtual function for drawing
    void draw() override {
        cout << "Drawing Circle" << endl;
    }

    // Override the pure virtual function for calculating the area
    double area() override {
        return 3.14159 * radius * radius;
    }
};

// Derived class inheriting from Shape
class Rectangle : public Shape {
private:
    double width;
    double height;

public:
    // Constructor
    Rectangle(double w, double h) : width(w), height(h) {}

    // Override the pure virtual function for drawing
    void draw() override {
        cout << "Drawing Rectangle" << endl;
    }

    // Override the pure virtual function for calculating the area
    double area() override {
        return width * height;
    }
};

int main() {
    // Create objects of derived classes
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);

    // Create pointers of base class type
    Shape* shape1 = &circle;
    Shape* shape2 = &rectangle;

    // Call the virtual functions
    shape1->draw(); // Calls Circle's draw
    cout << "Area: " << shape1->area() << endl;

    shape2->draw(); // Calls Rectangle's draw
    cout << "Area: " << shape2->area() << endl;

    return 0;
}

Output

Drawing Circle
Area: 78.5398
Drawing Rectangle
Area: 24

Explanation

  • The Shape class is an abstract base class with pure virtual functions draw and area.
  • The Circle and Rectangle classes inherit from Shape and provide their own implementations of the draw and area functions.
  • The main function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respective draw and area functions.

Conclusion

Pure virtual functions in C++ allow you to define abstract classes and achieve runtime polymorphism. By declaring pure virtual functions, you ensure that derived classes provide specific implementations for these functions. This chapter covered the basics of defining pure virtual functions, creating abstract classes, and using them in practical examples. Understanding and effectively using pure virtual functions is essential for writing flexible, reusable, and maintainable C++ programs.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top