Concepts / Virtual Functions

Virtual Functions

A class that contains at least one pure virtual function, marked with the = 0 suffix, is an abstract class.

  • Programming

Reading a Container Interface

Imagine a class that describes a container. It stores no data of its own. Instead, it lists the operations any container must support. The question to keep in mind while reading is simple: which of these member functions does the class promise to provide, and which does it leave for some other class to provide?

cpp
Notes on the code
  • push and pop are declared with = 0, so both are pure virtual functions
  • The destructor is virtual but has a body, so it is not pure
  • The class declares operations and their signatures but gives no implementation for push or pop

The declaration is an interface. It names the operations and their signatures, and it provides no implementation for the two operations that matter most. Whatever class eventually supplies those implementations is responsible for making the container actually work. The rest of this article explains what that responsibility means for the compiler and for you.

What do you think happens?

Could a program create an object of type Container directly, as in Container c;?

  • Yes, because the class has a destructor with a body

  • No, because the class contains pure virtual functions

Reveal answer
Answer:

No, because the class contains pure virtual functions

The restriction does not come from the class being large or from missing data members. It comes from the pure virtual functions marked with = 0.

Virtual Versus Pure Virtual

Two separate ideas are combined in each declaration of an interface. The first is the word virtual. In this context, virtual means that a function may be redefined later in a class derived from this one. A function declared virtual is called a virtual function.

Definition

A virtual function is a member function declared with the keyword virtual, which means a class derived from this one may redefine it.

The second idea is the suffix = 0. This suffix marks the function as pure virtual. A pure virtual function is one that some class derived from the interface must define. The declaration is therefore a requirement placed on future code rather than a complete function. The source treats this suffix as the mechanism that turns a class into an interface.

Definition

A pure virtual function is a virtual function declared with the suffix = 0. A class derived from the interface must define it.

Key point

A class that contains at least one pure virtual function, marked with the = 0 suffix, is an abstract class.

Reading the =0 Suffix

When you read a declaration, look at each member function and ask whether it ends in = 0 before the semicolon. The anatomy below takes one pure virtual declaration apart token by token.

virtualfunction may be redefinedin a derived classvoidreturn typepush(int value)function name andparameters= 0pure: derived class mustdefine it;ends the declaration
Which parts of a pure virtual declaration mark it as virtual and as pure, and what does each token mean?

The = 0 token is the only thing that separates a pure virtual function from an ordinary virtual function. A virtual declaration with a body, such as the virtual destructor in the Container example, has no = 0 suffix. It may be redefined in a derived class, but nothing forces a derived class to define it, so it does not make the class abstract.

Why an Abstract Class Cannot Be Created

An abstract class cannot be used to create an object on its own. It serves as an interface for derived classes. The Container interface declares what must exist, but it does not supply those operations, so it is not used to build objects. Only a derived class that supplies every missing operation is used to build objects.

Containerabstract: push and pop arepureArrayContainerconcrete: implements pushand popderives from
Which class declares the pure virtual functions, and which class inherits them and must implement them?

The diagram shows the relationship the code expresses. The interface sits at the top and declares what must exist. The derived class sits below and supplies those operations. The interface itself is not used to build objects; only the derived class is. The restriction on creating objects therefore lives in the interface, and the object-creating power lives in the derived class.

Tracing Which Functions Are Pure

To decide whether a class is abstract, scan every member function. Mark each one as pure, virtual with a body, or ordinary. Then ask a single question: does any function carry the = 0 suffix? The worked example below follows that trace.

Worked example

Classifying the Members of a Sensor Class

class Sensor {
public:
    virtual void read() = 0;
    virtual void reset() = 0;
    virtual void describe() {}
    virtual ~Sensor() {}
};

Is Sensor abstract, and which members are responsible?

  1. 1
    List the members

    There are four virtual member functions: read, reset, describe, and the destructor.

  2. 2
    Check each for = 0

    read ends in = 0, so it is pure. reset also ends in = 0, so it is pure. describe has a body and no = 0, so it is not pure. The destructor has a body and no = 0, so it is not pure.

  3. 3
    Apply the rule

    A class that contains a pure virtual function is abstract. Sensor contains two pure virtual functions, so it is abstract.

  4. 4
    Conclude about objects

    Sensor cannot be used to create an object on its own. A derived class must define both read and reset before it can be created.

Result

Sensor is abstract. The pure members are read and reset. describe and the virtual destructor are virtual but not pure, so they do not cause the restriction.

Completing a Derived Class

An interface becomes useful when a class derives from it and supplies the missing functions. The class below keeps its elements in a plain array and implements both pure virtual functions from the Container interface. It is an illustrative example written for this article.

cpp
Notes on the code
  • The class header names Container as its base, so it inherits both pure virtual functions
  • push is defined here, so it is no longer pure in this class
  • pop is defined here, so it is no longer pure in this class
  • Because no pure virtual function remains undefined, ArrayContainer can be created as an object
Derived classdeclaredpure functions inheritedSome pure functionsundefinedstill abstractEvery pure functiondefinedconcreteObject createdallowed only when concreteinherits pure functionsdefines the missing onesinstantiate
As a derived class defines each pure virtual function, when does it change from abstract, where objects cannot be created, to concrete, where objects can be created?

The key question in every case is whether all pure virtual functions have been given definitions in the class being created. A derived class that leaves one of them undefined still contains a pure virtual function, so it remains abstract. This is why the derived class has to match the interface completely before it can be used as an object.

Best practice

When a derived class cannot be instantiated, ask one question first: which pure virtual function from the interface is still missing a definition? Locating that single function usually explains the whole problem.

FeatureVirtual functionPure virtual function
Declaration formvirtual void f();virtual void f() = 0;
Can a derived class redefine it?YesYes
Must a derived class define it?NoYes, before objects can be created
Makes the class abstract?NoYes

Both kinds are open to redefinition, but only the pure kind forces a derived class to provide a definition.

Mistakes Beginners Make with Pure Virtuals

  • Common mistake

    Deciding a class is abstract because it is large or has no data members

    What it looks like
    class Logger { public: virtual void log(const char* msg) = 0; };
    Why it fails

    The restriction does not come from size or data members. It comes from the = 0 suffix.

    Do this instead

    Scan the member functions for = 0. The Logger above is abstract because of log, not because it has no data.

  • Common mistake

    Treating a virtual function with a body as pure

    What it looks like
    virtual ~Container() {}
    Why it fails

    This declaration is virtual, but it has no = 0 suffix and provides a body, so it is not pure.

    Do this instead

    A virtual function with a body does not make the class abstract. Only a pure virtual function does.

  • Common mistake

    Leaving one pure virtual function undefined in a derived class

    Why it fails

    The derived class still contains a pure virtual function, so it remains abstract and cannot be created.

    Do this instead

    Compare the derived class against every pure virtual function in the interface and define each missing one.

  • Common mistake

    Trying to create an object of the interface class itself, such as Container c; when Container still has pure virtual functions

Practice Classifying Classes

EASY

Consider this class: class Widget { public: virtual void draw() = 0; virtual void resize(int w) {} virtual ~Widget() {} }; Is Widget abstract? Name the member responsible, and state what a derived class must do before it can be created as an object.

Hints
  • Look for the = 0 suffix on each member function.
  • resize and the destructor have bodies and no = 0, so they are not pure.
  • A derived class must define every pure virtual function it inherits, which here means draw.

Key Takeaways

  • A pure virtual function is a virtual function marked with the = 0 suffix, and a class that contains one is an abstract class.
  • An abstract class cannot be used to create an object on its own; it serves as an interface for derived classes.
  • A derived class must define every pure virtual function it inherits before it can be created as an object. A virtual function with a body, such as a virtual destructor, is not pure and does not make a class abstract.
  • To predict whether a class is abstract, scan every member function for the = 0 suffix and check whether any is missing a definition in the derived class.

Related concepts

More concepts starting with V