OSC++.019: Pure Virtual Functions and Abstract Classes Basics

Diagram showing an abstract C++ base class with a pure virtual function inherited by two concrete derived classes that implement overrides.

A pure virtual function says: every concrete derived class must provide this behavior, but the base class does not provide the normal implementation that objects will use.

This lesson follows OSC++.018: Virtual Functions and Polymorphism Basics. That lesson showed how a base-class reference can call the correct overridden function at runtime. Now we take the next step: making some base-class functions required.

Start with the one line that changes everything

virtual void start() = 0;

The = 0 makes this a pure virtual function.

virtual void start() = 0;
│       │           │
│       │           └─ pure virtual
│       └──────────── function name
└──────────────────── runtime-polymorphic function

A class containing a pure virtual function is an abstract class. You cannot directly create an ordinary object of that abstract class.

The smallest useful example

#include <iostream>

class Machine {
public:
    virtual void start() = 0;
};

class Fan : public Machine {
public:
    void start() override {
        std::cout << "Fan starting\n";
    }
};

int main() {
    Fan fan;
    fan.start();
}

Output:

Fan starting

Machine defines the rule: every concrete machine must know how to start(). Fan satisfies that rule by providing an override.

Video 1: Abstract classes and pure virtual functions

Portfolio Courses — Abstract Classes and Pure Virtual Functions. This lesson explains why abstract base classes exist and how pure virtual functions require derived implementations.

Why can’t we instantiate the abstract class?

This will not compile:

Machine machine;

Why? Because Machine contains a pure virtual function. It describes a common interface, but it is intentionally incomplete as a concrete object type.

Machine
  │
  ├── says every machine must provide start()
  │
  └── does not represent one complete concrete machine

Fan
  └── provides start() → can be instantiated

Microsoft’s C++ documentation explains that a class with at least one pure virtual function is abstract and cannot be used to instantiate objects directly.

Reference: Microsoft Learn — Abstract Classes (C++).

Pure virtual vs. ordinary virtual

FunctionMeaning
virtual void start() { ... }The base class provides behavior that derived classes may override.
virtual void start() = 0;The function is pure virtual. A concrete derived class must provide a non-pure final override before objects of that derived type can be instantiated.

Think of the difference this way:

ordinary virtual:
"Here is a default behavior; replace it if needed."

pure virtual:
"This behavior is part of the interface; a concrete derived type must provide it."

What happens if the derived class does not override it?

class Machine {
public:
    virtual void start() = 0;
};

class Fan : public Machine {
    // no start() override
};

Fan is still abstract because its inherited pure virtual requirement has not been satisfied by a non-pure final override.

Fan fan;   // error: Fan is abstract

That is useful. The compiler helps prevent you from accidentally creating an incomplete concrete type.

Video 2: Pure virtual functions step by step

LearningLad — C++ Pure Virtual Functions and Abstract Classes. This walkthrough focuses on the syntax, base-class requirement, and derived-class implementation.

One interface, many implementations

Now add another concrete machine:

class Pump : public Machine {
public:
    void start() override {
        std::cout << "Pump starting\n";
    }
};

The hierarchy becomes:

          Machine
       start() = 0
          /   \
         /     \
       Fan     Pump
     start()  start()

Both classes obey the same interface while implementing the behavior differently.

Use the abstract class through a reference

void start_machine(Machine& machine) {
    machine.start();
}

Now the function can work with any concrete class derived from Machine that fulfills the interface:

Fan fan;
Pump pump;

start_machine(fan);
start_machine(pump);

Output:

Fan starting
Pump starting

This is the payoff: code can depend on the common Machine interface instead of being hard-coded to one specific machine type.

Abstract does not mean empty

An abstract class can still contain data members, constructors, ordinary member functions, and normal virtual functions.

#include <iostream>
#include <string>

class Machine {
protected:
    std::string name;

public:
    Machine(const std::string& machine_name)
        : name(machine_name) {}

    void show_name() const {
        std::cout << name << '\n';
    }

    virtual void start() = 0;
};

The class is abstract because of start() = 0, but it can still provide shared state and shared behavior to derived classes.

A practical data-center example

Imagine software that monitors several kinds of equipment. Every device must report status, but the details differ.

#include <iostream>

class Device {
public:
    virtual void report_status() const = 0;
};

class Server : public Device {
public:
    void report_status() const override {
        std::cout << "Server: online\n";
    }
};

class CoolingUnit : public Device {
public:
    void report_status() const override {
        std::cout << "Cooling unit: running\n";
    }
};

The monitoring code can ask every Device to report status without needing one completely separate interface for servers and cooling units.

ASIC-mining example

class Miner {
public:
    virtual double hashrate_th() const = 0;
};

class S21 : public Miner {
public:
    double hashrate_th() const override {
        return 200.0;
    }
};

class OtherMiner : public Miner {
public:
    double hashrate_th() const override {
        return 150.0;
    }
};

The base class defines the question—“What is your hashrate?”—while each miner model supplies the answer appropriate to that class.

Video 3: Beginner pure-virtual and abstract-class walkthrough

ProgrammingKnowledge — C++ Tutorial for Beginners: Pure Virtual Functions and Abstract Classes. Reinforces the syntax and why abstract classes are used as base interfaces.

Why use override on the derived function?

void start() override

override asks the compiler to verify that this function really overrides a virtual function from the base class.

For example, this typo is useful to catch:

class Machine {
public:
    virtual void start() = 0;
};

class Fan : public Machine {
public:
    void Start() override {   // capital S: does not match
    }
};

The compiler can tell you that Start() does not override start().

An abstract class can have more than one pure virtual function

class Device {
public:
    virtual void start() = 0;
    virtual void stop() = 0;
    virtual bool healthy() const = 0;
};

A concrete derived class must satisfy every remaining pure virtual requirement.

ConcreteDevice
  must provide:
  ├── start()
  ├── stop()
  └── healthy()

Pure virtual destructors are a special case

C++ allows a destructor to be pure virtual, but unlike an ordinary pure virtual member function, a pure virtual destructor still needs a definition because derived-object destruction eventually invokes the base destructor.

class Base {
public:
    virtual ~Base() = 0;
};

Base::~Base() = default;

You do not need to use this pattern yet. The important beginner rule is simpler: if a class is intended to be used polymorphically through base pointers, understand virtual destructors before owning/deleting derived objects through that base. A later lesson can go deeper into object lifetime.

Reference: cppreference — Abstract class and pure virtual function.

Common beginner mistakes

  • Trying to instantiate the abstract base class directly.
  • Forgetting = 0 when a function is supposed to be pure virtual.
  • Forgetting to override every required pure virtual function in a class that should be concrete.
  • Assuming an abstract class cannot contain constructors, fields, or ordinary functions.
  • Thinking = 0 means “assign zero to the function.” It is special C++ syntax declaring the function pure virtual.
  • Leaving off override and missing a signature mismatch.
  • Using inheritance only because it exists instead of because the derived types genuinely share the base interface.

Quick practice

  1. Create an abstract class named Sensor.
  2. Add a pure virtual function named read() that returns double.
  3. Create a class named TemperatureSensor that derives from Sensor.
  4. Override read().
  5. Create a TemperatureSensor object.
  6. Create a Sensor& reference to it and call read().
  7. Then temporarily remove the override and observe why the derived class becomes abstract.

Knowledge check

1. What does = 0 mean after a virtual function declaration?
It declares the function pure virtual.

2. What makes a class abstract?
In this beginner context, a class is abstract when it has at least one pure virtual function that remains pure as a final overrider.

3. Can you create a direct object of an abstract class?
No.

4. Can an abstract class contain normal member functions and data?
Yes.

5. What does a concrete derived class normally need to do?
Provide non-pure overrides for all inherited pure virtual requirements that remain unsatisfied.

Key takeaway

A pure virtual function defines required behavior in a base interface. A class with an unsatisfied pure virtual function is abstract and cannot be instantiated directly. Concrete derived classes complete the interface by providing overrides.

Abstract base class
        ↓
Defines required interface
        ↓
Concrete derived classes
        ↓
Provide the actual behavior
        ↓
One common interface, many implementations

Display note: all C++ examples and diagrams in this lesson are plain educational code blocks. They are not simulated VS Code, Windows, or Linux terminals, so no terminal color palette is invented or represented.

BitcoinVersus.Tech

Advertisement

BitcoinVersus.Tech advertisement.

Editor’s Note:

We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support our research initiatives, please donate here: 3C9o19EH5HSiwEPyCTmEKzxhNCbo2X6TTb

BitcoinVersus.tech is not a financial advisor. This media platform reports on financial subjects purely for informational purposes.

Leave a comment