C++ abstract class and pure virtual function are key building blocks for object-oriented design in C++. They let you define common behavior at a high level and force derived classes to implement specific functions. This page explains what they are, how they work, when to use them, and the most common mistakes beginners make, with clear, runnable examples.
- An abstract class cannot be instantiated and has at least one pure virtual function (e.g.,
virtual void f() = 0;). - Use base references/pointers to enable runtime polymorphism across derived types.
- Concrete derived classes must override every inherited pure virtual; use
overrideto let the compiler verify the signature. - Always give polymorphic bases a virtual destructor; a pure virtual destructor still needs a definition.
- Avoid calling virtual functions in constructors/destructors and avoid object slicing; prefer
std::unique_ptr<Base>or references.
What is an abstract class in C++?
An abstract class is a class that cannot be instantiated directly. In C++, a class becomes abstract when it declares (or inherits) at least one pure virtual function. You can still create pointers or references to an abstract class and use them to achieve runtime polymorphism, but you cannot create an object of the abstract type itself.
- Declaring a pure virtual function: use
= 0in the declaration. - Abstract classes can have constructors, data members, and non-virtual functions.
- They are often used as “interfaces” that define required behavior for derived classes.
Simple abstract class syntax
#class="cd-package">include <iostream>
struct Shape {
virtual void draw() const = 0; // pure virtual function
virtual ~Shape() = default; // always virtual destructor for polymorphic deletion
};If you try to do Shape s;, the compiler will error, because Shape is abstract.
Pure virtual function in C++
A pure virtual function in C++ is a virtual member function with no default implementation provided at the point of declaration, written with = 0. A class that has (or inherits) a pure virtual function is abstract.
- Syntax:
virtual ReturnType func(params) = 0; - You must override a pure virtual function in any concrete derived class to be instantiable.
- Advanced: a pure virtual function can still have an out-of-class definition; the class remains abstract.
Abstract class example in C++ (beginner-friendly)
Here is a minimal example showing polymorphism with an abstract base class and two derived classes.
#class="cd-package">include <iostream>
#class="cd-package">include <memory>
#class="cd-package">include <vector>
struct Shape {
virtual void draw() const = 0; // pure virtual
virtual ~Shape() = default; // virtual destructor
};
struct Circle : Shape {
void draw() const override {
std::cout << "Drawing Circlen";
}
};
struct Rectangle : Shape {
void draw() const override {
std::cout << "Drawing Rectanglen";
}
};
int main() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>());
shapes.push_back(std::make_unique<Rectangle>());
for (const auto& s : shapes) {
s->draw(); // runtime polymorphism
}
}Drawing Circle
Drawing RectangleIn this example, Shape is abstract because of the pure virtual function draw(). We store derived objects in a std::vector<std::unique_ptr<Shape>> and call draw() polymorphically.
Base& or Base* (e.g., s->draw()).How to create abstract class in C++ step by step
- Declare a base class with at least one pure virtual function using
= 0. - Give the base class a virtual destructor (often defaulted).
- Derive a concrete class and implement (override) every pure virtual function.
- Use pointers or references to the base class to enable polymorphism.
#class="cd-package">include <iostream>
#class="cd-package">include <memory>
class Animal {
class="cd-keyword cd-access">public:
virtual void speak() const = 0; // Step 1: pure virtual
virtual ~Animal() = default; // Step 2: virtual destructor
};
class Dog : class="cd-keyword cd-access">public Animal {
class="cd-keyword cd-access">public:
void speak() const override { // Step 3: implement (override)
std::cout << "Woof!n";
}
};
int main() {
std::unique_ptr<Animal> a = std::make_unique<Dog>(); // Step 4
a->speak();
}Woof!Overriding pure virtual functions in C++
When you override a pure virtual function in a derived class, prefer the override specifier. It lets the compiler check that you are actually overriding a virtual function from the base class.
#class="cd-package">include <iostream>
struct Base {
virtual void run() = 0;
virtual ~Base() = default;
};
struct Derived final : Base { // ___CDPHSTR0___ prevents further inheritance
void run() override { // ___CDPHSTR1___ ensures correct signature
std::cout << "Derived::runn";
}
};
int main() {
Derived d;
Base& b = d;
b.run();
}Derived::runTip: If you try to override run() in a class derived from Derived, the compiler will error because Derived is marked final.
Pure virtual function can still have a definition
This surprises many learners: a pure virtual function can have a body defined outside the class. The class remains abstract, but derived classes may call the base implementation explicitly.
#class="cd-package">include <iostream>
struct Base {
virtual void info() = 0; // pure virtual
virtual ~Base() = default;
};
void Base::info() { // out-of-class definition for a pure virtual
std::cout << "Base::info default behaviorn";
}
struct Derived : Base {
void info() override {
std::cout << "Derived: ";
Base::info(); // call base's definition if useful
}
};
int main() {
Derived d;
d.info();
}Derived: Base::info default behaviorPure virtual destructor example
If you declare a pure virtual destructor, you must still provide a definition for it. This allows proper cleanup through base pointers.
#class="cd-package">include <iostream>
struct Device {
virtual ~Device() = 0; // pure virtual destructor
};
Device::~Device() { // must provide a definition
std::cout << "Device destroyedn";
}
struct Keyboard : Device {
~Keyboard() override {
std::cout << "Keyboard destroyedn";
}
};
int main() {
Device* d = new Keyboard{};
delete d; // calls Keyboard::~Keyboard, then Device::~Device
}Keyboard destroyed
Device destroyedWhen to use abstract class in C++
Use an abstract class when:
- You need runtime polymorphism across a family of types.
- You want to define a common interface and force derived classes to implement required functions.
- You will work with objects via base pointers/references (e.g., from a factory, plugin system, or strategy pattern).
- You need dynamic dispatch that can be extended in separate translation units.
Alternatives:
- Templates and C++20 concepts for compile-time polymorphism (no virtual functions involved).
- Type erasure (e.g., “polymorphic value type”) when you want runtime polymorphism without inheritance.
Abstract base class vs concrete class in C++
| Feature | Abstract base class | Concrete class |
|---|---|---|
| Instantiation | Cannot be instantiated | Can be instantiated |
| Pure virtual functions | At least one | None required |
| Use case | Define interface and enable polymorphism | Provide complete behavior |
| Ownership and deletion | Delete via base pointer; base destructor should be virtual | Normal deletion of the object |
Difference between abstract class and interface in C++
C++ has no interface keyword. People often use “interface” to mean a class with only public pure virtual functions and a virtual destructor, and no data members.
| Aspect | Abstract class | Interface-like class (C++ style) |
|---|---|---|
| Members | May have data and function implementations | Only pure virtual functions, no data |
| Purpose | Can provide partial implementation and state | Defines behavior contract only |
| Flexibility | Good for base behavior + customization points | Good for clean, minimal APIs |
Common mistakes with abstract classes in C++
- Forgetting the virtual destructor in a polymorphic base. Without it, deleting a derived object via a base pointer is undefined behavior.
- Trying to instantiate the abstract base class. You must instantiate a concrete derived class.
- Not marking overrides with
override. This can hide bugs when signatures do not match perfectly. - Object slicing: passing/returning derived objects by value as the base type discards derived parts. Use pointers or references to the base.
- Calling virtual functions (especially pure virtual) inside constructors or destructors of the base class. Dynamic dispatch does not work there; calling a pure virtual in this context is undefined behavior.
- Expecting default arguments on virtual functions to dispatch dynamically. Default arguments are bound at compile time, not at runtime.
- Trying to make a member function template virtual. In C++, member function templates cannot be virtual.
How do pure virtual functions work in C++? (Quick recap)
- A pure virtual makes the class abstract.
- Derived classes must override it to become concrete (instantiable).
- Calls through base references/pointers resolve at runtime to the most-derived override.
- A pure virtual may still have an out-of-class definition; the base remains abstract.
FAQ: C++ abstract class and pure virtual function
What is an abstract class in C++ with a simple example?
An abstract class has at least one pure virtual function and cannot be instantiated. Example: a Shape class with virtual void draw() = 0; and derived classes like Circle and Rectangle that implement draw().
How do pure virtual functions work in C++?
They declare an interface that derived classes must implement. Calls to them via base references/pointers dispatch to the derived implementation at runtime. The base may still provide an out-of-class definition, but that does not make the class concrete.
Can we instantiate an abstract class in C++?
No. You cannot create an object of an abstract class. You can, however, create pointers or references to it and bind them to objects of derived concrete classes.
When should I use an abstract class in C++?
Use it to define a common API for a family of types and to enable runtime polymorphism, such as in plugins, GUI widgets, shapes, or drivers. Prefer minimal interfaces and consider alternatives like templates or concepts when compile-time polymorphism suffices.
What happens if a pure virtual function is not overridden?
The derived class remains abstract and cannot be instantiated. The compiler will prevent you from creating objects of that class.
Best practices and tips
- Keep abstract bases small: only the necessary pure virtuals and a virtual destructor.
- Use
overrideto catch signature mismatches; usefinalto stop further overrides. - Manage polymorphic objects via smart pointers (e.g.,
std::unique_ptr) to avoid memory leaks. - If the base owns resources or needs custom cleanup, ensure the destructor is virtual; a pure virtual destructor must still have a definition.
- Base declares at least one pure virtual (use
= 0) and has a virtual destructor. - Every concrete derived class overrides all inherited pure virtuals; mark them
overrideand match qualifiers (const, reference,noexcept). - No attempts to instantiate the abstract base; construct concrete derived types instead.
- No object slicing: store/manage via
Base&,Base*, orstd::unique_ptr<Base>(not by value asBase). - No virtual calls (especially pure virtual) in constructors/destructors of the base or derived classes.
- Avoid default arguments on virtuals (defaults bind statically and can surprise callers).
- If you declare a pure virtual destructor, provide an out-of-class definition.
- Consider alternatives (templates/concepts or type erasure) when runtime polymorphism isn’t required.
Want more beginner-friendly tutorials? Visit our C++ hub at CodDesire C++ Tutorials.
Sources / Further reading
- cppreference – Abstract class: https://en.cppreference.com/cpp/language/abstract_class
- cppreference – Virtual member functions: https://en.cppreference.com/cpp/language/virtual
- cppreference – override specifier: https://en.cppreference.com/cpp/language/override
- Microsoft Learn – Abstract classes (C++): https://learn.microsoft.com/en-us/cpp/cpp/abstract-classes-cpp?view=msvc-170
- Microsoft Learn – Virtual functions (C++): https://learn.microsoft.com/en-us/cpp/cpp/virtual-functions?view=msvc-170
- C++ Core Guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines


