What Is an Interface?
An interface defines a set of operations that a type must provide, without specifying how those operations are implemented.
It is like a contract: “Any class that claims to be of this interface type must provide these functions.”
Important points:
An interface says what can be done (method signatures).
Classes that implement the interface decide how it is done (method bodies).
Code that depends on the interface does not need to know which concrete class is behind it.
In Low Level Design, interfaces are used to:
Hide implementation details behind a common boundary.
Swap one implementation for another without changing the rest of the code.
Enable testability (e.g., using mock implementations).
Support polymorphism (one interface, many concrete classes).
Interfaces vs Classes (Conceptually)
So far, you’ve seen classes like User, Order, Ticket that have both data and behavior.
Interfaces are different:
A typical class might have:
Fields (data)
Method implementations (behavior code)
An interface focuses on:
Method signatures only (no implementation, no data fields in the pure version)
In many languages, there is a dedicated interface keyword.
In C++, there is no special keyword, but you can achieve the same idea using abstract classes with pure virtual functions.
How to Model an Interface in C++ (Abstract Class)
In C++, an “interface‑like” type is usually an abstract class that:
Has a public virtual destructor (good practice).
Has only pure virtual functions (functions with
= 0).Has no data members (when used as a pure interface).
General pattern:
Key ideas:
virtualmeans the function is meant to be overridden in derived classes.= 0makes the function pure virtual — no implementation here; the derived class must implement it.A class with at least one pure virtual function is abstract: you cannot create objects of it directly.
This is how you define a contract in C++.
Simple Example: Notification Interface
Imagine a system that can notify users in different ways: email, SMS, push, etc.
You do not want the rest of the system to know the details of each channel; it should just say “sendNotification”.
Define an interface:
Now, any concrete notifier must implement send.
Email implementation:
SMS implementation:
The rest of the system can talk to Notifier* or Notifier& and doesn’t care which specific notifier it is using.
Using Interfaces Through Pointers or References
The real power of interfaces appears when you use a base‑class pointer or reference.
Example function:
Usage:
Here:
sendWelcomeMessagedepends only on theNotifierinterface.You can pass any object that implements
Notifier.This is polymorphism in action: one function, different behavior based on actual object type.
In LLD terms: you depend on an abstraction, not on specific concrete classes.
Why Interfaces Are Important in LLD
Interfaces are a central tool when you want to:
Decouple high‑level code from low‑level details
For example, your
PaymentServicemight depend on aPaymentProcessorinterface, not on a specificRazorpayProcessororStripeProcessor.
Support multiple implementations
You might start with one payment gateway and later add another.
You might have different storage backends (in‑memory vs database) behind an
Repositoryinterface.
Improve testability
In tests, you can pass a
FakeNotifierorMockPaymentProcessorthat implements the same interface but has no real external dependencies.
Follow design principles
Interfaces help you follow ideas like dependency inversion (depend on abstractions, not concretions) and the open/closed principle (add new implementations without touching existing code).
In interviews, using interfaces thoughtfully shows that you design for extension and maintainability, not just for “getting it to work”.
Example: Payment Interface with Two Implementations
Consider a simple payment flow where the system can charge via card or via wallet.
Define the interface:
Card payment:
Wallet payment:
A service using the interface:
Using it:
Notice:
CheckoutServicedepends only onPaymentMethod.You can plug in any new payment implementation later (UPI, net banking, etc.) without changing.
CheckoutService.
This is exactly the kind of flexibility interfaces give you in LLD.
Interfaces and Abstract Classes: Relationship
In C++:
Any class with at least one pure virtual function is abstract.
If that abstract class has only pure virtual functions and no data members, it behaves like a pure interface.
Sometimes an abstract class can have some shared implementation plus some pure virtual functions — in that case, it is more of a “base class with abstract parts” than a pure interface.
For LLD diagrams and explanations, you often say:
“This is an interface that these classes implement.”
“This is a base class with some common code and some abstract methods.”
The key idea: interfaces define the shape of behavior; derived classes provide the details.
When Should You Introduce an Interface?
You do not need interfaces everywhere. They make sense when:
You know you will have multiple implementations (e.g., different notification channels, different payment providers, different storage systems).
You want to hide details behind a clear boundary.
You want the rest of the system to depend on behavior, not concrete classes.
You care about testability and future flexibility.
In the early stages of a design, you can mark certain classes in your notes as “this is an interface” and later express it as an abstract class in C++.
Common Mistakes with Interfaces
Some typical pitfalls:
Creating an interface when there is only one implementation and no clear reason to add more.
This adds unnecessary complexity.
Putting data fields into an interface‑style class.
Pure interfaces are usually kept free of data to avoid mixing responsibilities.
Calling interface methods without thinking about error handling or results.
For example, ignoring return values.
Tying interfaces to specific frameworks or libraries rather than to your domain.
Good interfaces should reflect your business logic, not just library details.
Being aware of these helps you use interfaces where they genuinely add value.
Summary
An interface defines what operations a type must support, without defining how those operations are implemented.
In C++, interfaces are modeled as abstract classes with pure virtual functions, and concrete classes implement those functions to provide real behavior.
You saw:
The conceptual difference between classes and interfaces.
How to declare an interface‑like abstract class in C++.
How can multiple implementations (email/SMS notifier, card/wallet payment) share a common interface?
How calling code can depend on interfaces instead of concrete types, enabling flexibility and testability.
When interfaces are appropriate in Low Level Design, and common mistakes to avoid.