Welcome to this engaging lesson on Abstract Classes and Pure Virtual Functions in C programming! This topic is crucial for understanding object-oriented programming (OOP) principles within the C environment. You'll learn about creating abstract base classes, defining pure virtual functions, and how these concepts enable a higher level of code organization and reusability.
In real-world applications, abstract classes and pure virtual functions are essential when you need to define a set of common methods or properties for a group of related classes while ensuring that certain methods are implemented by the derived classes.
Abstract Classes (also known as abstract base classes) are classes that cannot be instantiated directly. They serve as a blueprint for other classes, providing a standard interface that those classes must implement. In C, we achieve this by defining at least one pure virtual function. A pure virtual function is a function with no implementation in the abstract class and a = 0
specifier after its return type.
#include <stdio.h> // Standard C library
struct AbstractShape { // Declaring an abstract base class
virtual void draw() = 0; // Pure virtual function
};
Pure Virtual Functions are essential for ensuring that derived classes provide an implementation for the method, thus enforcing a common interface and polymorphic behavior.
Let's create a simple example where we have an abstract base class AbstractShape
, a concrete derived class Circle
implementing all the methods, and another derived class Square
that only provides the implementation for the draw()
method.
#include <stdio.h> // Standard C library
#include <math.h> // For M_PI constant
struct AbstractShape { // Abstract base class
virtual void draw() = 0;
};
struct Circle : public AbstractShape { // Derived concrete class
double radius;
Circle(double r) : radius(r) {}
void draw() override { // Implementing the pure virtual function
printf("Drawing a circle with radius: %f\n", radius);
}
};
struct Square : public AbstractShape { // Derived class with incomplete implementation
int side;
Square(int s) : side(s) {}
void draw() override { // Implementing the pure virtual function
printf("Drawing a square with side: %d\n", side);
}
};
void main() { // Main function
Circle circle(5.0);
Square square(3);
circle.draw();
square.draw();
}
What causes it: Failing to provide a concrete implementation for all non-pure virtual functions in the abstract base class.
// Bad C code example that triggers the error
struct AbstractShape { // Abstract base class with missing implementation
void draw();
};
Error message:
error: 'AbstractShape' does not have any field members
Solution: Provide a concrete implementation for all non-pure virtual functions in the abstract base class.
// Corrected C code
struct AbstractShape { // Abstract base class with complete implementation
void draw() {} // Empty implementation for demonstration purposes
int getArea() { return 0; } // Another example of a non-pure virtual function
};
Why it happens: A pure virtual function is only one aspect of an abstract base class. To be considered abstract, the class must not have any concrete implementations for its non-pure virtual functions.
How to prevent it: Ensure that you provide a complete implementation for all non-pure virtual functions in the abstract base class or mark them as pure virtual (with = 0
) if they are intended to be overridden by derived classes.
What causes it: Trying to call a pure virtual function directly, either from an abstract base class instance or from another derived class that does not provide an implementation for the function.
// Bad C code example that triggers the error
struct AbstractShape { // Abstract base class with a pure virtual function
virtual void draw() = 0;
};
int main() { // Main function
AbstractShape shape; // Creating an abstract base class instance
shape.draw(); // Attempting to call the pure virtual function directly
}
Error message: This error would typically be a runtime error, as it depends on the C++ Standard Library used in your project. For simplicity, we will not provide a specific error message here.
Solution: Call the pure virtual function only from derived classes that provide an implementation for the function.
// Corrected C code
struct Circle : public AbstractShape { // Derived concrete class with implementation for draw()
void draw() override {
printf("Drawing a circle\n");
}
};
int main() { // Main function
Circle circle; // Creating a derived concrete class instance
circle.draw(); // Calling the pure virtual function from the derived class
}
Why it happens: A pure virtual function is meant to be implemented by derived classes, and as such, they should only be called from those derived classes or other functions within them. Attempting to call a pure virtual function directly violates this principle.
How to prevent it: Ensure that pure virtual functions are called only from derived classes that provide their implementation.
new
operator when creating instances of derived classes and ensure proper memory deallocation with delete
.