Abstraction is an important concept of Object-Oriented Programming (OOP). It means hiding unnecessary implementation details and showing only the essential features of an object or system.
Abstraction means showing only the important information and hiding unnecessary implementation details.
For example, when you use an ATM, you select options such as withdrawal or balance enquiry. You do not need to know the internal implementation of the ATM software.
class ATM {
public:
void withdraw() {
// Complex internal process
std::cout <<
"Money withdrawn";
}
};
The main idea of abstraction is:
Abstraction allows programmers to focus on what an object does instead of how it does it.
Consider a car.
You do not need to understand every internal engine operation to drive the car.
This is a simple real-world example of abstraction.
In C++, abstraction can be achieved using classes and access specifiers.
class BankAccount {
private:
double balance;
public:
void deposit(double amount) {
balance += amount;
}
};
The user can call deposit() without directly accessing
the internal balance variable.
Private members can hide internal data and implementation details from code outside the class.
class Student {
private:
int marks;
public:
void setMarks(int m) {
if(m >= 0 && m <= 100) {
marks = m;
}
}
int getMarks() {
return marks;
}
};
The internal variable marks is hidden from direct external
access.
The functions or members that are available to users of a class form part of its public interface.
class Calculator {
private:
int result;
public:
void add(int a, int b) {
result = a + b;
}
int getResult() {
return result;
}
};
Users interact with the class through its public functions rather than directly modifying its internal data.
A class can hide complex operations behind a simple public function.
class EmailService {
private:
void connectToServer() {
// Complex implementation
}
void prepareMessage() {
// Complex implementation
}
public:
void sendEmail() {
connectToServer();
prepareMessage();
std::cout <<
"Email sent";
}
};
The user only needs to call sendEmail().
An abstract class is a class that contains at least one pure virtual function.
class Shape {
public:
virtual double area() = 0;
};
The class provides an interface but does not provide an implementation
for area().
A pure virtual function is declared by assigning 0 to a
virtual function.
class Shape {
public:
virtual void draw() = 0;
};
The derived class must provide an implementation if it is to be instantiable.
An abstract class cannot normally be used to create an object directly.
class Shape {
public:
virtual void draw() = 0;
};
// Shape shape; // Not allowed
Instead, a derived class can implement the pure virtual function.
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void draw() override {
std::cout <<
"Drawing Circle";
}
};
int main() {
Circle circle;
circle.draw();
return 0;
}
The Shape class defines the interface, while
Circle provides the implementation.
Virtual functions allow a base class to define an interface that can be implemented differently by derived classes.
class Animal {
public:
virtual void sound() = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void sound() override {
std::cout <<
"Dog barks";
}
};
Abstraction and polymorphism often work together.
class Animal {
public:
virtual void sound() = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void sound() override {
std::cout <<
"Dog barks";
}
};
class Cat : public Animal {
public:
void sound() override {
std::cout <<
"Cat meows";
}
};
The base class provides the abstract interface, while derived classes provide different implementations.
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void draw() override {
std::cout <<
"Circle";
}
};
int main() {
Circle circle;
Shape* shape = &circle;
shape->draw();
return 0;
}
The pointer uses the abstract interface instead of depending directly on implementation details.
An abstract class can define operations that every derived class is expected to provide.
class Payment {
public:
virtual void pay(
double amount
) = 0;
virtual ~Payment() = default;
};
Every concrete payment class can implement pay() in its
own way.
class Payment {
public:
virtual void pay(
double amount
) = 0;
virtual ~Payment() = default;
};
class CashPayment : public Payment {
public:
void pay(
double amount
) override {
std::cout <<
"Cash payment: "
<< amount;
}
};
class CardPayment : public Payment {
public:
void pay(
double amount
) override {
std::cout <<
"Card payment: "
<< amount;
}
};
The abstract class defines what a payment class must do, while the derived classes decide how to do it.
Encapsulation and abstraction are related but different concepts.
| Concept | Main Purpose |
|---|---|
| Encapsulation | Bundles data and functions together and controls access. |
| Abstraction | Hides unnecessary implementation details and exposes essential behavior. |
Both concepts help make programs easier to use and maintain.
Consider a bank account.
class BankAccount {
private:
double balance;
public:
void deposit(double amount) {
balance += amount;
}
void withdraw(double amount) {
if(amount <= balance) {
balance -= amount;
}
}
};
class ATM {
private:
void verifyPIN() {
std::cout <<
"PIN verified";
}
void connectBank() {
std::cout <<
"Bank connected";
}
public:
void withdraw() {
verifyPIN();
connectBank();
std::cout <<
"Cash withdrawn";
}
};
The user only calls withdraw(). The internal operations
remain hidden.
class Vehicle {
public:
virtual void start() = 0;
virtual ~Vehicle() = default;
};
class Car : public Vehicle {
public:
void start() override {
std::cout <<
"Car engine started";
}
};
The user only needs to know that the vehicle can be started. The internal starting mechanism is hidden.
An abstract class can contain multiple pure virtual functions.
class Shape {
public:
virtual double area() = 0;
virtual double perimeter() = 0;
virtual ~Shape() = default;
};
A concrete derived class must implement both functions.
#include <iostream>
class Shape {
public:
virtual double area() = 0;
virtual void display() = 0;
virtual ~Shape() = default;
};
class Rectangle : public Shape {
private:
double length;
double width;
public:
Rectangle(
double l,
double w
)
: length(l),
width(w) {
}
double area() override {
return length * width;
}
void display() override {
std::cout <<
"Area: "
<< area();
}
};
int main() {
Rectangle rectangle(10, 5);
rectangle.display();
return 0;
}
The user of Rectangle can call area() without
needing to know how the calculation is internally performed.
Access specifiers help control which parts of a class are visible to other code.
| Specifier | Access |
|---|---|
| public | Accessible through the class interface. |
| private | Accessible only inside the class and permitted friends. |
| protected | Accessible inside the class and derived classes, subject to access rules. |
Using access control helps hide implementation details.
override in derived classes.A good abstraction provides a simple and meaningful interface.
class Notification {
public:
virtual void send(
std::string message
) = 0;
virtual ~Notification() = default;
};
Different notification classes can implement the same interface.
class EmailNotification :
public Notification {
public:
void send(
std::string message
) override {
std::cout <<
"Email: "
<< message;
}
};
#include <iostream>
class Payment {
public:
virtual void pay(
double amount
) = 0;
virtual ~Payment() = default;
};
class UPI : public Payment {
public:
void pay(
double amount
) override {
std::cout <<
"UPI payment: "
<< amount
<< std::endl;
}
};
class Card : public Payment {
public:
void pay(
double amount
) override {
std::cout <<
"Card payment: "
<< amount
<< std::endl;
}
};
void processPayment(
Payment& payment,
double amount
) {
payment.pay(amount);
}
int main() {
UPI upi;
Card card;
processPayment(upi, 500);
processPayment(card, 1000);
return 0;
}
The processPayment() function works with the abstract
Payment interface instead of depending on one specific
payment implementation.
| Concept | Meaning |
|---|---|
| Abstraction | Showing essential features while hiding unnecessary implementation details. |
| Abstract Class | A class containing at least one pure virtual function. |
| Pure Virtual Function | A virtual function declared with = 0. |
| Interface | A set of operations through which code interacts with an object. |
| Encapsulation | Bundling data and functions together and controlling access. |
| Polymorphism | Allowing the same interface to represent different implementations. |
class Shape {
public:
virtual double area() = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r)
: radius(r) {
}
double area() override {
return 3.14159 *
radius *
radius;
}
};
Here, Shape defines what a shape must provide, while
Circle provides the actual implementation. This is a
fundamental example of abstraction in C++.
= 0.Question: What is the main purpose of abstraction in C++?