What an interface is
An interface describes what a class can do, without saying how it does it and without storing any data. A Truck, a Robot and a Drone are different kinds of things, but all three can move. If you write the promise "I can move" once, as an interface, any code that needs something movable can work with all three.
Inheritance models "is a": a Dog is an Animal. An interface models "can do": a Dog can speak. The same class can be both.
How C++ expresses an interface
C++ has no interface keyword. By convention, a class that contains only pure virtual functions plays that role. A pure virtual function is a virtual function declared with = 0 instead of a body:
class Speaker {
public:
virtual void speak() = 0;
virtual ~Speaker() = default;
};
Three things are worth noticing:
- The class is abstract. A class with at least one pure virtual function can't be instantiated.
Speaker s;does not compile. - The members are public. A
classis private by default, so thepublic:label is what lets other code callspeakthrough aSpeaker. - The destructor is virtual. Code that holds a
Speaker*maydeleteit. Without a virtual destructor, deleting a derived object through a base pointer is undefined behaviour.= defaultasks the compiler to generate the usual empty body.
Implementing an interface
A class implements the interface by inheriting from it publicly and providing a body for every pure virtual function:
class Dog : public Speaker {
public:
void speak() override { cout << "Woof" << endl; }
};
The override keyword is optional but valuable. It tells the compiler that this function must replace a virtual function of a base class. If you misspell the name or change the parameter list, the code stops compiling instead of silently creating an unrelated function.
Public inheritance means a Dog can be used wherever a Speaker is expected. That is the point of an interface: code written against Speaker doesn't need to know which concrete class it has.
vector<Speaker*> speakers = { new Dog, new Cat };
for (Speaker* s : speakers) {
s->speak(); // calls Dog::speak, then Cat::speak
}
for (Speaker* s : speakers) delete s;
Which speak runs is decided when the program runs, based on the real type of each object. This is runtime polymorphism.
Interface versus abstract class
| Abstract class | Interface | |
|---|---|---|
| Data members | Allowed | Usually none |
| Method bodies | Some are allowed | None, only pure virtual functions |
| Combining several | Possible but risky | A class can implement many |
| Models | "is a" | "can do" |
In C++ the difference is a matter of discipline, not syntax. Both are classes with pure virtual functions. If you add a data member or a function with a body, you have an abstract base class instead of a pure interface.
Implementing several interfaces
C++ supports multiple inheritance, so a class can list several interfaces:
class Flyer {
public:
virtual void fly() = 0;
virtual ~Flyer() = default;
};
class Bird : public Speaker, public Flyer {
public:
void speak() override { cout << "Tweet" << endl; }
void fly() override { cout << "Flap" << endl; }
};
Multiple inheritance is safe here because the interfaces carry no data, so there is no shared state to conflict. A Bird can be passed as a Speaker& or as a Flyer&.
Common mistakes
- Leaving one pure virtual function unimplemented. The derived class stays abstract, and
Dog rex;fails to compile. If an interface has three functions, the concrete class needs all three. - Forgetting
publicbefore the base name. In aclass,class Dog : Speakermeans private inheritance, so outside code can't treat aDogas aSpeaker. - Forgetting
public:inside the derived class. Thespeakfunction would be private, and callingrex.speak()from another class fails. - Omitting the virtual destructor. Everything seems to work until a
deletethrough a base pointer skips the derived destructor. - Different signatures.
void speak() const overridedoesn't matchvoid speak(). Withoverridethe compiler reports it.
The lesson's exercise
The Speaker interface is already written. The task is a Dog class whose speak() prints Woof, and the lesson's code then calls it from mainFunction.
- Declare the class. Write
class Dog : public Speaker, open apublic:section, and close the class with};. The semicolon after the closing brace is required for every class. - Implement the function. Add
void speak() overridewith a body that printsWoofusingcout.
class Dog : public Speaker {
public:
void speak() override {
cout << "Woof" << endl;
}
};
With this in place, Dog rex; rex.speak(); prints:
Woof
Key takeaways
- An interface in C++ is a class made only of pure virtual functions (
= 0) and a virtual destructor. - A class implements it with public inheritance and a body for every pure virtual function.
- Mark overriding functions with
overrideso the compiler checks the signature. - Interfaces express "can do", and one class can implement many of them.
- Always give an interface a virtual destructor.