Start learning free

LESSON 184 OF 343 · OBJECT-ORIENTED PROGRAMMING

Abstract Classes in C++: Pure Virtual Functions

Lesson Read the full explanation

TL ; DR:

An abstract class is a class you can't instantiate directly — it's a half-finished template. It can declare methods with no body (abstract methods) that any concrete subclass must implement.


class Animal {
public:
    virtual void speak() = 0;   // pure virtual — Animal is abstract
    virtual ~Animal() = default;
};
class Dog : public Animal {
public:
    void speak() override { cout << "Woof" << endl; }
};


Full lesson:

Sometimes you want to capture shared behavior across a family of classes without committing to one concrete implementation. For example, every Animal can speak(), but exactly how depends on whether it's a Dog or a Cat. That's what abstract classes are for.

Two superpowers

  1. You can't write new Animal() directly — the compiler/runtime stops you. You have to pick a concrete subclass.
  2. Any subclass MUST implement every abstract method, or the compiler/runtime complains. The abstract class is a contract with teeth.

Mixing abstract and concrete

An abstract class can also have concrete methods (with bodies) and fields. Those are shared by all subclasses for free, just like normal inheritance. Only the methods marked abstract require an override.

Notes by language

  • C# / Java — keyword abstract on the class and on the method.
  • Python — inherit from abc.ABC and decorate the method with @abstractmethod.
  • JavaScript — no built-in support. The convention is a parent class whose method throws an error if not overridden.
  • C++ — a method ending with = 0 is "pure virtual"; a class with any pure virtual method is abstract.

Your task

The abstract Animal class is already defined. Create a concrete Dog subclass and implement the speak method so it prints "Woof". The harness builds a Dog and calls speak().

Expected output:

Woof
STEP 1 OF 2
    Ctrl + Enter to check

    C++ · OBJECT-ORIENTED PROGRAMMING

    Abstract Classes in C++, explained

    A class that is only a template

    Sometimes you want to describe what a family of classes can do without saying how. Every Animal can speak(), but a dog and a cat do it differently, and a generic animal has no sound at all. An abstract class captures this: it declares the operations and leaves the implementations to its subclasses. You can't create an object of an abstract class directly. You make objects of its concrete subclasses.

    C++ has no abstract keyword. A class becomes abstract by having at least one pure virtual function.

    Pure virtual functions

    A pure virtual function is a virtual function declared with = 0 and no body:

    class Animal {
    public:
        virtual void speak() = 0;
        virtual ~Animal() = default;
    };
    

    The = 0 does not mean "returns zero". It is the syntax that says "no implementation here; derived classes must provide one". It gives the class two properties:

    1. It can't be instantiated. Animal a; and new Animal() are compile errors. GCC reports cannot declare variable 'a' to be of abstract type 'Animal'.
    2. Subclasses must implement every pure virtual function to become concrete. A subclass that doesn't is abstract too, so declaring a variable of it fails with the same error.

    The abstract class is therefore a contract, and the compiler enforces it.

    Using it

    A concrete subclass fills in the missing function. Marking it override asks the compiler to check that it really replaces the virtual function:

    class Dog : public Animal {
    public:
        void speak() override { cout << "Woof" << endl; }
    };
    

    You can't make an Animal object, but you can still use Animal* and Animal&. They are how polymorphism works with abstract classes: Animal* a = new Dog(); followed by a->speak(); prints Woof.

    Mixing abstract and concrete members

    An abstract class can have normal members too, such as data and ordinary functions with bodies. Subclasses inherit them as usual, and a concrete function can call a pure virtual one:

    class Animal {
    public:
        virtual void speak() = 0;
        virtual ~Animal() = default;
        void intro() {
            cout << "I say: ";
            speak();
        }
    };
    

    For a Dog that implements speak, calling intro() prints I say: Woof. The shared part is written once, and each subclass supplies the variable part. Only the functions marked = 0 are required to be overridden.

    C++ even lets a pure virtual function have a body, defined outside the class. A derived class still has to override it, but it can call the base body explicitly with Animal::speak(). This is rare, and you can ignore it for now.

    The destructor line

    The line virtual ~Animal() = default; appears here for the same reason as in the polymorphism lesson. If objects are deleted through an Animal*, the destructor must be virtual. Here = default asks the compiler to write the ordinary destructor, and virtual makes it dispatch to the real class. Abstract classes are almost always used through base pointers, so a virtual destructor is a normal part of them.

    The lesson's exercise

    The abstract Animal class and a mainFunction that creates a Dog named rex and calls speak() are given. The task is to define Dog. The program should print:

    Woof
    1. Below Animal and above Solution, declare class Dog : public Animal with a public: section. Without public, rex.speak() would not be callable from outside.
    2. Inside it, write void speak() override with a body that prints "Woof" and endl. The signature must match the pure virtual function: same name, no parameters, a void return type.

    The solution in C++

    class Animal {
    public:
        virtual void speak() = 0;
        virtual ~Animal() = default;
    };
    
    class Dog : public Animal {
    public:
        void speak() override {
            cout << "Woof" << endl;
        }
    };
    
    class Solution {
    public:
        void mainFunction() {
            Dog rex;
            rex.speak();
        }
    };
    

    The line Dog rex; works only because Dog is concrete: it overrides the one pure virtual function. If you leave out speak, the compiler rejects the line, saying Dog is of abstract type. Dog has no constructor of its own, and Animal has none either, so the compiler-generated default constructors are enough.

    Common mistakes

    • Trying to create the abstract class. Animal a; and new Animal() both fail.
    • Misspelling or changing the signature. A function like void speak(int times) doesn't implement the pure virtual one, and Dog stays abstract. With override, the compiler tells you at that line.
    • Forgetting public before the base class. Inheritance is private by default for a class, which makes the inherited speak inaccessible from outside.
    • Writing a body inside the class after = 0. That is not valid syntax.
    • Leaving the base destructor non-virtual and deleting through a base pointer.

    Key takeaways

    • A class with at least one pure virtual function (virtual void f() = 0;) is abstract and can't be instantiated.
    • Subclasses must override every pure virtual function to be usable as objects.
    • Abstract classes can still hold data and ordinary functions, and they are used through pointers and references.
    • Give them a virtual destructor.
    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free