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 functiondraw
. - The
Circle
andRectangle
classes inherit fromShape
and provide their own implementations of thedraw
function. - The
main
function creates objects ofCircle
andRectangle
, uses base class pointers to point to these objects, and calls thedraw
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 functionmakeSound
. - The
Dog
andCat
classes inherit fromAnimal
and provide their own implementations of themakeSound
function. - The
main
function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respectivemakeSound
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 functionprocessPayment
. - The
CreditCardPayment
andPayPalPayment
classes inherit fromPayment
and provide their own implementations of theprocessPayment
function. - The
main
function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respectiveprocessPayment
functions.
Guidelines for Using Pure Virtual Functions
- Define Abstract Base Classes: Use pure virtual functions to define abstract base classes that serve as interfaces for derived classes.
- 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.
- 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 functionsdraw
andarea
. - The
Circle
andRectangle
classes inherit fromShape
and provide their own implementations of thedraw
andarea
functions. - The
main
function demonstrates polymorphic behavior with base class pointers pointing to derived class objects and calling their respectivedraw
andarea
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.