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:
- It can't be instantiated.
Animal a;andnew Animal()are compile errors. GCC reportscannot declare variable 'a' to be of abstract type 'Animal'. - 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
- Below
Animaland aboveSolution, declareclass Dog : public Animalwith apublic:section. Withoutpublic,rex.speak()would not be callable from outside. - Inside it, write
void speak() overridewith a body that prints"Woof"andendl. The signature must match the pure virtual function: same name, no parameters, avoidreturn 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;andnew Animal()both fail. - Misspelling or changing the signature. A function like
void speak(int times)doesn't implement the pure virtual one, andDogstays abstract. Withoverride, the compiler tells you at that line. - Forgetting
publicbefore the base class. Inheritance is private by default for aclass, which makes the inheritedspeakinaccessible 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.