SyntaxStudy
Sign Up
C++ Pure Virtual Functions and Abstract Classes
C++ Beginner 1 min read

Pure Virtual Functions and Abstract Classes

A pure virtual function is declared by appending '= 0' to a virtual function declaration. Any class containing at least one pure virtual function is an abstract class and cannot be instantiated directly. Abstract classes serve as interfaces or partially implemented base classes, forcing derived classes to provide concrete implementations of the required operations. Abstract base classes are the C++ mechanism for defining contracts. A well-designed abstract class expresses what a family of types can do without dictating how they do it, enabling dependency inversion: high-level modules depend on abstractions, not on concrete implementations. This principle is central to testable, extensible software architecture. It is legal to provide an implementation for a pure virtual function in the base class. Such implementations can be called explicitly via the scope-resolution operator and are useful when all derived classes share common logic but must still override the function. The pure-virtual destructor is the standard idiom for creating abstract classes with no other virtual functions.
Example
#include <iostream>
#include <string>
#include <vector>
#include <memory>

// Abstract base — defines the interface
class IRenderer {
public:
    virtual ~IRenderer() = default;

    virtual void beginFrame() = 0;
    virtual void drawTriangle(float x, float y, float z) = 0;
    virtual void endFrame()   = 0;

    // Non-pure helper that calls pure virtuals
    void renderScene(const std::vector<float>& vertices) {
        beginFrame();
        for (std::size_t i = 0; i + 2 < vertices.size(); i += 3)
            drawTriangle(vertices[i], vertices[i+1], vertices[i+2]);
        endFrame();
    }
};

// Concrete implementation A
class OpenGLRenderer : public IRenderer {
public:
    void beginFrame()  override { std::cout << "[GL] Begin frame\n"; }
    void drawTriangle(float x, float y, float z) override {
        std::cout << "[GL] Triangle (" << x<<","<<y<<","<<z<<")\n";
    }
    void endFrame()    override { std::cout << "[GL] End frame\n";   }
};

// Concrete implementation B
class ConsoleRenderer : public IRenderer {
public:
    void beginFrame()  override { std::cout << "[CON] ---\n"; }
    void drawTriangle(float x, float y, float z) override {
        std::cout << "[CON] tri " << x<<" "<<y<<" "<<z<<"\n";
    }
    void endFrame()    override { std::cout << "[CON] ---\n"; }
};

int main() {
    std::vector<float> verts = {0,0,0, 1,0,0, 0,1,0};

    std::unique_ptr<IRenderer> r = std::make_unique<OpenGLRenderer>();
    r->renderScene(verts);

    r = std::make_unique<ConsoleRenderer>();
    r->renderScene(verts);

    return 0;
}