CppAbstract Classes

Abstract Classes

An abstract class is a class that defines an interface — a set of operations any derived class must provide — without necessarily implementing all of them itself. In C++, a class becomes abstract by declaring at least one pure virtual function.

Pure virtual functions

A pure virtual function is declared with = 0 instead of a body. It says: “every concrete (instantiable) derived class must provide an implementation of this — the base class does not.”

Declaring a pure virtual function

CPP
class Shape {
public:
    virtual double area() const = 0; // pure virtual — no implementation here
    virtual ~Shape() = default;      // virtual destructor (see previous page)
};
Note
A class with at least one pure virtual function **cannot be instantiated**. `Shape shape;` or `new Shape()` are both compile errors — `Shape` only exists to be inherited from, never to be created directly.
A worked example: Shape, Circle, Rectangle

An abstract base class with two concrete derived classes

CPP
#include <iostream>

class Shape {
public:
    virtual double area() const = 0; // must be implemented by derived classes
    virtual ~Shape() = default;
};

class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}

    double area() const override {
        return 3.14159265 * radius * radius;
    }

private:
    double radius;
};

class Rectangle : public Shape {
public:
    Rectangle(double w, double h) : width(w), height(h) {}

    double area() const override {
        return width * height;
    }

private:
    double width, height;
};

int main() {
    Circle c(4.0);
    Rectangle r(3.0, 5.0);

    Shape* shapes[] = { &c, &r };
    for (Shape* s : shapes) {
        std::cout << "Area: " << s->area() << "\n"; // polymorphic call
    }
}

Shape* shapes[] holds pointers to two different concrete types, but the loop body doesn't need to know which is which — s->area() dispatches to Circle::area() or Rectangle::area() correctly at runtime, exactly the runtime polymorphism described on the previous two pages. This is the real payoff of an abstract base class: code that works with Shape* automatically works with any shape anyone adds in the future.

What if a derived class doesn't implement it?

If a derived class fails to override every pure virtual function it inherits, it remains abstract itself — it inherits the unimplemented obligation along with everything else, and it too cannot be instantiated until something eventually provides the missing implementation.

A derived class that stays abstract

CPP
class Triangle : public Shape {
    // area() is not overridden here!
};

int main() {
    // Triangle t; // Error: cannot instantiate abstract class 'Triangle'
    //             // (area() is still pure virtual in Triangle)
}
Interfaces vs. partial implementations

An abstract class can mix pure virtual functions (the interface) with ordinary member functions and data (shared implementation) — Shape above provides a concrete virtual destructor alongside its pure virtual area(). A class made up entirely of pure virtual functions with no data acts like a pure interface, similar to what other languages call an “interface” type.

What's next
  • Abstract classes are often paired with operator overloading so custom types work naturally with +, ==, <<, and other operators — covered next.