Monday, October 12, 2026
HomeC ProgrammingAbstraction in OOP: Summary Lessons, Interfaces, Protocols

Abstraction in OOP: Summary Lessons, Interfaces, Protocols


A operate that reads the system clock to resolve between “Good morning” and “Good night” is difficult to check: its output is dependent upon when the check runs. Change it to simply accept any object that may report the hour, and the issue disappears. This system passes in the true clock; the check passes in a clock caught at 8:00. The operate by no means is aware of which one it has. That’s abstraction: code written towards what one thing does, not how it does it.

This information explains abstraction as an object-oriented idea, with the identical instance in C++, Java and Python: what abstraction means, how summary courses and interfaces specific it, how Python does it with summary base courses and protocols, and methods to inform a helpful abstraction from an pointless one. Each program was run for this text on Ubuntu 24.04 with GCC 13.3 and Clang 18.1.3 (-std=c++17 -Wall -Wextra -pedantic -Werror), OpenJDK 21 (javac -Xlint:all -Werror) and Python 3.11, 3.12 and three.13 (-W error), and each output under is captured verbatim. The code is in a GitHub repository whose construct repeats these checks on every commit.

The Brief Reply

What’s abstraction in OOP? Describing a kind by what it does (its operations and their guarantees) and conserving the way it does them out of view. Code that makes use of the kind relies upon solely on that description, so any implementation that retains the guarantees can be utilized as a replacement.

What’s the distinction between abstraction and encapsulation? Abstraction decides what the surface world sees; encapsulation protects what it doesn’t see. An interface is an abstraction; non-public fields guarded by strategies are encapsulation. Most well-designed courses use each.

What’s the distinction between an summary class and an interface? An summary class can maintain fields and dealing code alongside the operations it leaves unimplemented, and a category can prolong just one. An interface (in Java) states operations solely, other than default strategies, and a category can implement many. C++ has no interface key phrase; a category with solely pure digital features performs that function.

What Is Abstraction?

Abstraction in object-oriented programming is the follow of representing one thing by its important operations whereas hiding the small print of how these operations are carried out. In code, it normally takes the type of an summary sort, an summary class or an interface, that declares what operations exist and what they promise, with concrete courses that present the implementations. Code written towards the summary sort works with each implementation.

Abstraction is older than object-oriented programming, and it seems at a number of ranges:

Type What’s hidden Instance
Procedural abstraction The steps of an algorithm Calling kind() with out figuring out which sorting algorithm it makes use of
Knowledge abstraction How a worth is saved An account exposes steadiness(); whether or not it shops the steadiness or provides up its historical past is invisible
Summary sort Which class does the work greeting() takes any Clock, actual or fastened

Barbara Liskov and Stephen Zilles described the second kind in 1974 as summary information varieties: a kind outlined completely by the operations that may be carried out on it. Object-oriented languages add the third kind, by which a number of courses implement the identical summary sort and callers can’t inform them aside. That substitution can also be what makes inheritance and polymorphism helpful.

One Abstraction in C++, Java and Python

The Clock sort under guarantees one factor: hour() returns the present hour, from 0 to 23. SystemClock retains the promise by studying the true time; FixedClock retains it by returning no matter hour it was given. greeting() is written towards Clock alone:

C++:

// greeting.cpp - abstraction: greeting() is dependent upon what a clock does
// (report the hour), not on how any explicit clock finds it out.
#embrace <ctime>
#embrace <iomanip>
#embrace <iostream>
#embrace <string>

class Clock {
public:
    digital ~Clock() = default;
    digital int hour() const = 0;  // 0 to 23; each concrete clock should say how
};

class SystemClock : public Clock {
public:
    int hour() const override {
        std::time_t now = std::time(nullptr);
        return std::localtime(&now)->tm_hour;
    }
};

class FixedClock : public Clock {
public:
    specific FixedClock(int hour) : hour_(hour) {}
    int hour() const override { return hour_; }

non-public:
    int hour_;
};

std::string greeting(const Clock& clock) {
    int h = clock.hour();
    if (h < 12) return "Good morning";
    if (h < 18) return "Good afternoon";
    return "Good night";
}

int major() {
    for (int h : {8, 14, 21}) {
        FixedClock clock(h);
        std::cout << std::setw(2) << std::setfill('0') << h << ":00 -> " << greeting(clock) << 'n';
    }

    SystemClock now;
    std::string g = greeting(now);
    bool identified = g == "Good morning" || g == "Good afternoon" || g == "Good night";
    std::cout << "system clock: hour in 0..23 = " << std::boolalpha
              << (now.hour() >= 0 && now.hour() <= 23) << ", greeting identified = " << identified << 'n';

    // Clock c;  // doesn't compile: Clock is summary
}

Java:

// Greeting.java - abstraction: greeting() is dependent upon what a clock does
// (report the hour), not on how any explicit clock finds it out.
import java.time.LocalTime;
import java.util.Checklist;

public remaining class Greeting {
    interface Clock {
        int hour();  // 0 to 23; each implementation should say how
    }

    static remaining class SystemClock implements Clock {
        @Override
        public int hour() { return LocalTime.now().getHour(); }
    }

    document FixedClock(int hour) implements Clock {}  // the document's hour() implements Clock

    static String greeting(Clock clock) {
        int h = clock.hour();
        if (h < 12) return "Good morning";
        if (h < 18) return "Good afternoon";
        return "Good night";
    }

    public static void major(String[] args) {
        for (int h : new int[] {8, 14, 21}) {
            System.out.printf("%02d:00 -> %spercentn", h, greeting(new FixedClock(h)));
        }

        Clock now = new SystemClock();
        String g = greeting(now);
        boolean identified = Checklist.of("Good morning", "Good afternoon", "Good night").comprises(g);
        System.out.println("system clock: hour in 0..23 = " + (now.hour() >= 0 && now.hour() <= 23)
                           + ", greeting identified = " + identified);

        // Clock c = new Clock();  // doesn't compile: Clock is summary
    }
}

Python:

"""greeting.py - abstraction: greeting() is dependent upon what a clock does
(report the hour), not on how any explicit clock finds it out."""
from abc import ABC, abstractmethod
from datetime import datetime


class Clock(ABC):
    @abstractmethod
    def hour(self) -> int:
        """0 to 23; each concrete clock should say how."""


class SystemClock(Clock):
    def hour(self) -> int:
        return datetime.now().hour


class FixedClock(Clock):
    def __init__(self, hour: int) -> None:
        self._hour = hour

    def hour(self) -> int:
        return self._hour


def greeting(clock: Clock) -> str:
    h = clock.hour()
    if h < 12:
        return "Good morning"
    if h < 18:
        return "Good afternoon"
    return "Good night"


for h in (8, 14, 21):
    print(f"{h:02d}:00 -> {greeting(FixedClock(h))}")

now = SystemClock()
identified = greeting(now) in ("Good morning", "Good afternoon", "Good night")
print(f"system clock: hour in 0..23 = {str(0 <= now.hour() <= 23).decrease()}, greeting identified = {str(identified).decrease()}")

# Clock()  # raises TypeError: Clock is summary

Output (equivalent for all three):

08:00 -> Good morning
14:00 -> Good afternoon
21:00 -> Good night
system clock: hour in 0..23 = true, greeting identified = true

The primary three traces are the explanation the abstraction exists. greeting() was checked at 8:00, 14:00 and 21:00 in a single run, and the end result is identical each time, which is what an automatic check wants. The final line makes use of the true clock; its actual greeting is dependent upon when this system runs, so this system prints solely that the hour was in vary and the greeting was one of many three. Neither line wanted any change to greeting().

Every language declares the abstraction in a different way:

  • C++ makes hour() a pure digital operate (= 0). A category with at the least one pure digital operate is summary, and every derived class should override it earlier than objects of that class can exist. The main points, together with pure digital destructors, are in pure digital features in C++.
  • Java makes use of an interface. FixedClock is a document, whose generated accessor hour() implements the interface with no additional code.
  • Python inherits from abc.ABC and marks hour() with @abstractmethod.


Abstraction: greeting() relies upon solely on what a Clock does
The courses in greeting.cpp, Greeting.java and greeting.py

greeting(clock)
the code that makes use of the abstraction calls hour()

Clock
summary: no objects of its personal
hour() -> 0 to 23

SystemClock
reads the true time
used when this system runs

FixedClock(8)
returns the hour it was given
used to check greeting() implement

greeting() by no means
names SystemClock
or FixedClock.
A brand new clock wants
no change to it.

With FixedClock(8):
08:00 -> Good
morning
each run

C++
digital int hour() const = 0;
Java
interface Clock { int hour(); }
Python
class Clock(ABC):
with
@abstractmethod
on hour()
greeting() is written towards Clock, so any clock will do. A program can cross the system clock and a check can cross a hard and fast one, with no change to greeting(); Clock itself can’t be instantiated in any of the three languages.

Summary Sorts Can’t Be Created

An summary sort describes objects however has none of its personal, and all three languages refuse to create one. C++ and Java refuse at compile time; Python refuses when the thing is created:

Language Assertion Consequence
C++ Clock c; GCC: can not declare variable 'c' to be of summary sort 'Clock'
Java Clock c = new Clock(); Clock is summary; can't be instantiated
Python 3.12 and three.13 Clock() TypeError: Cannot instantiate summary class Clock with out an implementation for summary technique 'hour'
Python 3.11 Clock() TypeError: Cannot instantiate summary class Clock with summary technique hour

The identical examine catches a subclass that forgets an operation: in C++, a category derived from Clock with out an hour() override is summary too, and declaring one produced the identical GCC error. Python’s wording modified in 3.12, which is why the Python program within the subsequent part prints its personal message quite than the interpreter’s.

Summary Lessons vs Interfaces

Each declare operations with out (totally) implementing them. They differ in what else they will include and in what number of a category can inherit:

Side Summary class Interface
C++ A category with at the least one pure digital operate; can have information members and carried out features No key phrase; by conference a category with solely pure digital features and a digital destructor
Java summary class; fields, constructors, any entry stage; a category extends just one interface; no occasion fields, summary and default strategies (Java 8+), plus static and personal helpers; a category implements any quantity
Python A category derived from abc.ABC with @abstractmethod strategies; checked when an object is created typing.Protocol; matched by any class with the correct strategies, checked by static sort checkers
Use it for A household of intently associated courses that share code or state A functionality that unrelated courses can supply

Java’s tutorial places the selection in the identical phrases: think about an summary class to share code amongst a number of intently associated courses, and an interface when unrelated courses would implement it (Summary Lessons In comparison with Interfaces). Clock is an interface by that check: a system clock and a check clock share nothing besides the promise.

C++ has a second solution to specific an abstraction that has no run-time price: a template accepts any sort with the required operations, checked at compile time, and C++20 ideas let the necessities be named and acknowledged. The usual library’s personal clocks (std::chrono::system_clock, steady_clock) work that method. Java’s commonplace library additionally has an summary clock, java.time.Clock, with Clock.fastened(...) for exams, which is identical thought as the instance above.

Abstraction in Python: ABCs and Protocols

Python gives two methods to state an abstraction, and so they examine various things. An summary base class requires implementations to inherit from it, and refuses to create an object that has not carried out each summary technique. A protocol (typing.Protocol, added in Python 3.8) requires solely {that a} class has the correct strategies. The Python documentation calls this structural subtyping, or “static duck-typing” (typing documentation):

"""protocol.py - two methods to state an abstraction in Python.
An ABC is checked when an object is created; a Protocol is checked solely
by a static sort checker, and any object with the correct technique works."""
from abc import ABC, abstractmethod
from typing import Protocol


class Clock(Protocol):
    def hour(self) -> int: ...


class Sundial:  # no base class: it matches Clock by having hour()
    def hour(self) -> int:
        return 9


def greeting(clock: Clock) -> str:
    h = clock.hour()
    if h < 12:
        return "Good morning"
    if h < 18:
        return "Good afternoon"
    return "Good night"


print(f"Sundial (no base class) -> {greeting(Sundial())}")


class AbstractClock(ABC):
    @abstractmethod
    def hour(self) -> int: ...


class BrokenClock(AbstractClock):  # forgot to implement hour()
    cross


attempt:
    BrokenClock()
besides TypeError:
    print("BrokenClock() -> TypeError: the summary technique hour() was not carried out")

Output:

Sundial (no base class) -> Good morning
BrokenClock() -> TypeError: the summary technique hour() was not carried out

Sundial by no means mentions Clock, but greeting() accepted it, as a result of it has an hour() technique. A sort checker equivalent to mypy would settle for it too, because it matches the protocol’s form. BrokenClock, then again, inherits from an summary base class and forgot hour(), so creating it failed instantly, earlier than any code may name the lacking technique. The abc documentation states the rule: a category with summary strategies “can’t be instantiated until all of its summary strategies and properties are overridden.”

Use an ABC while you need the assure enforced at run time and implementations to declare their intent by inheriting. Use a protocol when implementations come from code you don’t management, or when duck typing is sufficient and also you need a sort checker to substantiate it.

Selecting Good Abstractions

An abstraction is price having when it lets code ignore a element it shouldn’t depend upon. 4 habits assist:

  1. Identify the abstraction for what it does. Clock.hour() says what callers get. A reputation equivalent to TimeHelper.getLocalHourFromSystem() describes one implementation, and the abstraction is misplaced.
  2. Hold it small. Clock has one technique, so a brand new implementation takes just a few traces (one, as a Java document). An interface with fifteen strategies is difficult to implement for a check, and most callers use just a few of them.
  3. Put it at a boundary. Time, recordsdata, networks, databases and randomness are the place abstractions pay for themselves first: they’re sluggish or unpredictable, and exams want to exchange them.
  4. Look ahead to the second implementation. An interface with one implementation and no check double provides a file and a layer of indirection, and its design is usually flawed when the second case lastly arrives. Extract it when it’s wanted.

Each abstraction additionally hides one thing that may matter. Joel Spolsky referred to as this the Legislation of Leaky Abstractions: “All non-trivial abstractions, to some extent, are leaky” (Joel on Software program, 2002). The Clock above is a small instance. SystemClock returns the hour within the laptop’s native time zone, which the Clock interface doesn’t point out, so the identical program, run on a server set to UTC, greets a person in Tokyo with “Good morning” at 7 p.m. Tokyo time. A greater Clock would state its time zone, or take one as a parameter. Good abstractions say which particulars they disguise and which of them the caller nonetheless wants to consider.

Abstraction vs Encapsulation

The 2 are taught collectively and sometimes confused:

Side Abstraction Encapsulation
Query it solutions What does this kind supply, no matter implementation? Who could change this object’s information, and the way?
Most important instruments Summary courses, interfaces, protocols Non-public fields, strategies that examine each change
Degree Design: which operations exist Implementation: how one class protects its state
Within the examples greeting() accepts any Clock An account’s steadiness modifications solely by way of withdraw

They help one another. An abstraction is simply as dependable because the implementations behind it, and encapsulation is what retains these implementations legitimate. The safety aspect is roofed in encapsulation in object-oriented programming.

Key Takeaways

  • Abstraction describes a kind by what it does and hides how. Code written towards the summary sort works with each implementation.
  • Summary varieties can’t be instantiated. C++ and Java reject Clock at compile time; Python raises TypeError when the thing is created.
  • An summary class can share code and state; an interface states a functionality. In C++ each are courses with pure digital features; in Python they map to ABCs and protocols.
  • Abstractions make code testable. A hard and fast clock let one run examine thrice of day, with the identical end result on each run.
  • Each non-trivial abstraction leaks someplace. The system clock’s time zone is a element the Clock interface doesn’t point out however callers might have.

Conclusion

Abstraction is a call about what code is allowed to depend upon. When greeting() is dependent upon “one thing that is aware of the hour” as a substitute of the system clock, it turns into testable, and a brand new form of clock prices nothing. C++, Java and Python every have their very own syntax for that call: pure digital features, interfaces, and summary base courses or protocols. In all three, the helpful questions are which operations callers actually need, and what the abstraction ought to admit it’s hiding.

The idea pages on this collection cowl the remainder of the image: courses and objects are the constructing blocks, encapsulation protects their state, and inheritance lets one summary sort have many implementations. Extra subjects are collected within the OOP part.

Supply Code and Exams

abstraction-concepts

All applications on this web page are within the oop/abstraction-concepts listing of the MYCPLUS C++ examples repository.

Construct and check:

bash exams/run_tests.sh g++

What the construct checks. On Linux, with GCC and with Clang, it compiles the C++ program with -Wall -Wextra -pedantic -Werror, compiles the Java program with javac -Xlint:all -Werror on Java 21, runs the Python applications with -W error on Python 3.12, and checks that each program prints precisely the output proven on this web page. Python 3.11 and three.13 have been checked regionally and produced the identical output. The compile errors and the TypeError messages within the desk have been produced by briefly including the statements proven; they don’t seem to be a part of the automated construct.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments