C++ Abstraction
What is Abstraction?
Abstraction means hiding complex implementation details and exposing only the essential interface. In C++, abstraction is achieved through abstract classes and pure virtual functions.
- A pure virtual function is declared with
= 0— it has no implementation in the base class. - A class with at least one pure virtual function is an abstract class — you cannot instantiate it directly.
- Derived classes must override all pure virtual functions to be instantiable.
#include <iostream>
#include <string>
using namespace std;
// Abstract class — cannot be instantiated
class PaymentMethod {
public:
// Pure virtual functions — MUST be overridden
virtual bool processPayment(double amount) = 0;
virtual string getType() const = 0;
// Concrete method — shared by all derived classes
void printReceipt(double amount) {
if (processPayment(amount)) {
cout << "[" << getType() << "] Payment of $"
<< amount << " successful." << endl;
} else {
cout << "[" << getType() << "] Payment failed." << endl;
}
}
virtual ~PaymentMethod() {}
};
class CreditCard : public PaymentMethod {
double limit;
public:
CreditCard(double limit) : limit(limit) {}
bool processPayment(double amount) override {
return amount <= limit;
}
string getType() const override { return "Credit Card"; }
};
class PayPal : public PaymentMethod {
double balance;
public:
PayPal(double balance) : balance(balance) {}
bool processPayment(double amount) override {
if (amount <= balance) { balance -= amount; return true; }
return false;
}
string getType() const override { return "PayPal"; }
};
int main() {
// PaymentMethod pm; // ERROR: cannot instantiate abstract class
PaymentMethod *methods[] = {
new CreditCard(1000),
new PayPal(50)
};
methods[0]->printReceipt(200); // Credit Card: success
methods[1]->printReceipt(200); // PayPal: failed (only $50)
for (auto m : methods) delete m;
return 0;
}
Interface Pattern (Pure Abstract Class)
A class with only pure virtual functions acts as an interface — it defines a contract that all implementing classes must fulfill.
#include <iostream>
using namespace std;
// Interface (pure abstract class)
class ILogger {
public:
virtual void log(const string &msg) = 0;
virtual void error(const string &msg) = 0;
virtual ~ILogger() {}
};
class ConsoleLogger : public ILogger {
public:
void log(const string &msg) override {
cout << "[LOG] " << msg << endl;
}
void error(const string &msg) override {
cerr << "[ERROR] " << msg << endl;
}
};
class FileLogger : public ILogger {
public:
void log(const string &msg) override {
// In real code: write to file
cout << "[FILE LOG] " << msg << endl;
}
void error(const string &msg) override {
cout << "[FILE ERROR] " << msg << endl;
}
};
void runApp(ILogger &logger) {
logger.log("Application started");
logger.error("Something went wrong");
}
int main() {
ConsoleLogger cl;
FileLogger fl;
runApp(cl); // uses ConsoleLogger
runApp(fl); // uses FileLogger — same function, different behaviour
return 0;
}