Introduction
Abstraction is one of the four pillars of OOP (alongside Encapsulation, Inheritance, Polymorphism).
It means hiding complex implementation details and exposing only what’s necessary.
The user of a class/function only needs to know what it does, not how it does it.
In C++, abstraction is achieved via abstract classes , interfaces (all-pure-virtual classes), and access modifiers .
Real-World Analogy
A car — you use the steering wheel, pedals, and gear shift. You don’t need to know how the engine combustion works internally.
A TV remote — press a button, channel changes. The IR signal encoding is hidden.
Advantages
Reduces complexity — users interact with a simple interface.
Improves maintainability — internal changes don’t affect users.
Enables code reuse and polymorphism.
Enforces separation of concerns.
Disadvantages
Over-abstraction can make code harder to trace and debug.
Adds indirection — slight performance overhead (vtable).
Requires careful design upfront.
Types of Abstraction
Data Abstraction
Hiding internal data representation — expose only through controlled methods.
Achieved via private/protected members + public getters/setters.
class BankAccount {
private:
double balance; // hidden — user can't access directly
public:
BankAccount ( double initial ) : balance (initial) {}
void deposit ( double amount ) {
if (amount > 0 ) balance += amount;
}
void withdraw ( double amount ) {
if (amount > 0 && amount <= balance) balance -= amount;
}
double getBalance () const { return balance; }
};
BankAccount acc ( 1000.0 );
acc. deposit ( 500 );
acc. withdraw ( 200 );
std ::cout << acc. getBalance (); // 1300
// acc.balance = 99999; // ERROR — private
Procedural Abstraction
Hiding the steps of an algorithm behind a function name.
Caller only knows the function signature, not the internal logic.
// User calls sort() — doesn't need to know it's introsort internally
#include <algorithm>
#include <vector>
std ::vector <int> v = { 5 , 2 , 8 , 1 , 9 };
std :: sort (v. begin (), v. end ());
// [1, 2, 5, 8, 9] — how it sorted is abstracted away
Abstract Class Abstraction
Define a common interface via pure virtual functions.
Each subclass provides its own implementation.
class Logger {
public:
virtual void log ( const std :: string & msg ) = 0 ;
virtual ~Logger () {}
};
class ConsoleLogger : public Logger {
public:
void log ( const std :: string & msg ) override {
std ::cout << "[Console] " << msg << " \n " ;
}
};
class FileLogger : public Logger {
public:
void log ( const std :: string & msg ) override {
// write to file — implementation hidden
std ::cout << "[File] " << msg << " \n " ;
}
};
// User only knows about Logger interface
void process ( Logger & logger ) {
logger. log ( "Processing started" );
logger. log ( "Processing done" );
}
ConsoleLogger cl;
process (cl);
// [Console] Processing started
// [Console] Processing done
C++ Examples
Shape Abstraction
#include <iostream>
#include <cmath>
class Shape {
public:
virtual double area () = 0 ;
virtual double perimeter () = 0 ;
virtual void describe () {
std ::cout << "Area: " << area ()
<< ", Perimeter: " << perimeter () << " \n " ;
}
virtual ~Shape () {}
};
class Circle : public Shape {
double r;
public:
Circle ( double r ) : r (r) {}
double area () override { return M_PI * r * r; }
double perimeter () override { return 2 * M_PI * r; }
};
class Square : public Shape {
double side;
public:
Square ( double s ) : side (s) {}
double area () override { return side * side; }
double perimeter () override { return 4 * side; }
};
int main () {
Shape * c = new Circle ( 5 );
Shape * s = new Square ( 4 );
c-> describe (); // Area: 78.539..., Perimeter: 31.415...
s-> describe (); // Area: 16, Perimeter: 16
delete c; delete s;
}
Payment System Abstraction
class PaymentProcessor {
public:
virtual bool processPayment ( double amount ) = 0 ;
virtual std :: string getProviderName () = 0 ;
virtual ~PaymentProcessor () {}
};
class StripeProcessor : public PaymentProcessor {
public:
bool processPayment ( double amount ) override {
std ::cout << "Stripe: charging $" << amount << " \n " ;
return true ; // internal Stripe API calls hidden
}
std :: string getProviderName () override { return "Stripe" ; }
};
class PayPalProcessor : public PaymentProcessor {
public:
bool processPayment ( double amount ) override {
std ::cout << "PayPal: charging $" << amount << " \n " ;
return true ;
}
std :: string getProviderName () override { return "PayPal" ; }
};
void checkout ( PaymentProcessor & processor , double total ) {
if (processor. processPayment (total))
std ::cout << "Payment via " << processor. getProviderName () << " successful \n " ;
}
StripeProcessor stripe;
checkout (stripe, 99.99 );
// Stripe: charging $99.99
// Payment via Stripe successful
Abstraction vs Encapsulation
These two are related but distinct concepts.
Concept What it does How in C++
Abstraction Hides complexity, shows interface Abstract classes, pure virtual
Encapsulation Bundles data + methods, restricts private/protected members
direct access to internal state
Abstraction = design-level concept (what to expose).
Encapsulation = implementation-level concept (how to protect data).
Key Takeaways
Abstraction = show what , hide how .
Achieved in C++ via abstract classes (pure virtual), access modifiers, and well-designed APIs.
Reduces coupling — callers depend on interfaces, not implementations.
Combine with encapsulation for clean, maintainable OOP design.