What Is an Interface in C++ Programming?
In C++, an interface is an architectural blueprint rather than a
dedicated language keyword, achieved programmatically through pure
abstract classes. Because C++ lacks a built-in interface
keyword like Java or C#, developers define an interface by declaring a
class that contains only pure virtual functions and a virtual
destructor, with no member variables or implementation logic. This
article explains how C++ achieves interface-based design, breaks down
the syntax required to create and implement one, and highlights best
practices for ensuring safe, polymorphic behavior.
Defining an Interface with Pure Virtual Functions
In C++, an abstract class becomes an interface when it contains no
state (member variables) and every member function is declared as "pure
virtual." A pure virtual function is declared by assigning
= 0 to a virtual function declaration, signaling to the
compiler that derived classes must provide the concrete
implementation.
class ILogger {
public:
virtual ~ILogger() = default;
virtual void log(const std::string& message) = 0;
virtual void setLogLevel(int level) = 0;
};By convention, interface names often begin with an uppercase
I (e.g., ILogger, IShape), though
this is a stylistic choice rather than a compiler requirement. Using
struct instead of class is also common because
members of a struct default to public
visibility, reducing boilerplate.
Key Components of a C++ Interface
To function correctly and safely as an interface, a class must adhere to specific rules:
- Pure Virtual Methods: Every method that defines an
action of the interface must use the
virtualspecifier and end with= 0. This prevents the interface itself from being instantiated. - Virtual Destructor: An interface must always define
a virtual destructor (typically
virtual ~InterfaceName() = default;). When deleting a derived object through a pointer to the base interface, a non-virtual destructor results in undefined behavior and resource leaks. - No Non-Static Data Members: An interface should define behavior, not state. Adding member variables introduces implementation details and violates the principle of separation of interface and implementation.
Implementing an Interface
A concrete class implements an interface through public inheritance. The derived class must override every pure virtual function to be instantiable; if it fails to implement even one pure virtual function, it remains an abstract class.
#include <iostream>
#include <string>
class ConsoleLogger : public ILogger {
public:
void log(const std::string& message) override {
std::cout << "[Console] " << message << std::endl;
}
void setLogLevel(int level) override {
logLevel_ = level;
}
private:
int logLevel_ = 0;
};The override specifier explicitly tells the compiler
that the function is intended to override a virtual function from a base
class, catching signature mismatches at compile time.
Using Interfaces for Polymorphism and Decoupling
Once an interface is defined, client code interacts with implementations exclusively through pointers or references to the interface type. This decouples the consumer from the concrete class, enabling loose coupling, dependency injection, and straightforward unit testing with mock objects.
void processTransaction(ILogger& logger) {
logger.log("Transaction started.");
// Process business logic...
logger.log("Transaction completed successfully.");
}
int main() {
ConsoleLogger consoleLogger;
processTransaction(consoleLogger);
return 0;
}By using pure abstract classes, C++ delivers the full utility of interface-driven design, enforcing clear contracts across codebases while maintaining the language's native runtime polymorphism.