Skip to content

Abstract Classes

Abstract Classes#

An abstract class is a class that cannot be instantiated directly and contains one or more abstract methods (without implementations) that must be implemented by subclasses. Abstract classes provide both concrete methods (with implementations) and abstract method declarations, creating a template that subclasses must complete.

Abstract classes bridge the gap between interfaces (no implementation) and concrete classes (complete implementation), following the principle of "code what you know, abstract what varies".

Abstract Class Structure#

graph TD
    A[Abstract Class] --> B[Concrete Methods]
    A --> C[Abstract Methods]

    B --> D["Implemented logic<br/>Shared by all subclasses"]
    C --> E["Method signatures only<br/>Must be implemented"]

    style A fill:#e3f2fd
    style B fill:#c8e6c9
    style C fill:#ffcdd2

Inheritance and Implementation#

graph TD
    A[Abstract Instrument] --> B[Guitar]
    A --> C[Piano]

    A --> D["tune() - concrete"]
    A --> E["play() - abstract"]

    B --> F["Inherits tune()"]
    B --> G["Implements play()"]

    C --> H["Inherits tune()"]
    C --> I["Implements play()"]

    style A fill:#e3f2fd
    style D fill:#c8e6c9
    style E fill:#ffcdd2
    style F fill:#c8e6c9
    style H fill:#c8e6c9
    style G fill:#fff3e0
    style I fill:#fff3e0

When to Use Abstract Classes#

Abstract classes are ideal when you have:

  • Shared functionality that should be implemented once
  • Specialized behavior that must vary between subclasses
  • Clear hierarchical relationships between related concepts

Language Examples#

public abstract class Instrument {
    public abstract void play();

    public void tune() {
        System.out.println("Tuning the instrument!");
    }
}

public class Guitar extends Instrument {
    @Override
    public void play() {
        System.out.println("Strumming the guitar!");
    }
}
abstract class Instrument {
    abstract fun play()

    fun tune() {
        println("Tuning the instrument!")
    }
}

class Guitar : Instrument() {
    override fun play() {
        println("Strumming the guitar!")
    }
}
abstract class Instrument {
    abstract play(): void;

    tune(): void {
        console.log("Tuning the instrument!");
    }
}

class Guitar extends Instrument {
    play(): void {
        console.log("Strumming the guitar!");
    }
}
abstract class Instrument {
    void play();

    void tune() {
        print("Tuning the instrument!");
    }
}

class Guitar extends Instrument {
    @override
    void play() {
        print("Strumming the guitar!");
    }
}
class Instrument {
    func play() {
        fatalError("This method must be overridden")
    }

    func tune() {
        print("Tuning the instrument!")
    }
}

class Guitar: Instrument {
    override func play() {
        print("Strumming the guitar!")
    }
}
from abc import ABC, abstractmethod

class Instrument(ABC):
    @abstractmethod
    def play(self):
        pass

    def tune(self):
        print("Tuning the instrument!")

class Guitar(Instrument):
    def play(self):
        print("Strumming the guitar!")