C++ Interface Design
In this page:
Pure Interfaces
An interface in C++ is conventionally represented by an abstract class made up entirely of pure virtual functions with no data members of its own — it establishes a contract that every derived class implementing it must fulfill.
Example: Pure Interfaces
#include <iostream>
class Printable {
public:
virtual void print() = 0;
};
class Document : public Printable {
public:
void print() override { std::cout << "Printing document" << std::endl; }
};
int main() {
Document d;
d.print();
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Implementing Interfaces
To implement an interface, a class inherits from the interface class and supplies a concrete override for every one of its pure virtual methods; only once all of them are implemented does the derived class become instantiable.
Example: Implementing Interfaces
#include <iostream>
class Drawable {
public:
virtual void draw() = 0;
};
class Circle : public Drawable {
public:
void draw() override { std::cout << "Circle" << std::endl; }
};
int main() {
Circle c;
c.draw();
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Multiple Interfaces
Unlike languages that limit a class to one base class, C++ allows multiple inheritance, so a single class can implement several distinct interfaces at once, each contributing its own separate contract that the class must satisfy.
Example: Multiple Interfaces
#include <iostream>
class Printable {
public:
virtual void print() = 0;
};
class Savable {
public:
virtual void save() = 0;
};
class Document : public Printable, public Savable {
public:
void print() override { std::cout << "Printing" << std::endl; }
void save() override { std::cout << "Saving" << std::endl; }
};
int main() {
Document d;
d.print();
d.save();
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Loose Coupling
Designing against interfaces rather than concrete classes promotes loose coupling: code that only interacts through an interface pointer doesn't need to know which concrete implementation is behind it, so swapping in a different implementation later doesn't ripple through the rest of the program.
Example: Loose Coupling
#include <iostream>
#include <string>
class Logger {
public:
virtual void log(std::string msg) = 0;
};
class ConsoleLogger : public Logger {
public:
void log(std::string msg) override { std::cout << msg << std::endl; }
};
void process(Logger &logger) {
logger.log("Processing complete");
}
int main() {
ConsoleLogger logger;
process(logger);
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Dependency Inversion
This style of design supports the Dependency Inversion principle, which says high-level modules should depend on abstract interfaces rather than directly on low-level concrete classes — making the overall system easier to extend and easier to test in isolation.
Example: Dependency Inversion
#include <iostream>
class Notifier {
public:
virtual void notify() = 0;
};
class EmailNotifier : public Notifier {
public:
void notify() override { std::cout << "Email sent" << std::endl; }
};
class App {
Notifier ¬ifier;
public:
App(Notifier &n) : notifier(n) {}
void run() { notifier.notify(); }
};
int main() {
EmailNotifier email;
App app(email);
app.run();
return 0;
}
Login to try C/C++/Java/PHP code in the editor
Chapter Quiz — Complete all 11 topics to unlock
0/11 topics done
Complete these topics first: