An abstract class is a class that cannot be instantiated directly — you can never write new Shape() if Shape is abstract. It exists purely to be extended, providing a partial implementation that concrete subclasses complete.
abstract class Employee {
protected name
protected baseSalary
function __construct(name, baseSalary) {
this.name = name
this.baseSalary = baseSalary
}
// Concrete method — shared, fully implemented, inherited as-is
function getName(): string {
return this.name
}
// Abstract method — no body; each subclass MUST provide its own
abstract function calculateBonus(): number
function getTotalPay(): number {
return this.baseSalary + this.calculateBonus()
}
}
class SalesEmployee extends Employee {
function calculateBonus(): number {
return this.baseSalary * 0.1 // 10% commission-style bonus
}
}
class EngineerEmployee extends Employee {
function calculateBonus(): number {
return 500 // flat annual bonus
}
}
// employee = new Employee("X", 1000) // ERROR — cannot instantiate an abstract class
sales = new SalesEmployee("Alice", 3000)
print(sales.getTotalPay()) // uses the shared getTotalPay(), calling SalesEmployee's own calculateBonus()
Why abstract classes are useful: they let you share real, working code (getName(), getTotalPay()) across a family of related classes, while still forcing each subclass to supply the pieces that genuinely differ (calculateBonus()). This is different from a plain interface, which cannot share any implementation at all (in the traditional sense), and different from a regular parent class, which doesn't force subclasses to override anything.
An abstract class with zero abstract methods is legal in most languages but somewhat unusual — the main point of an abstract class is usually to combine shared implementation with at least one required, subclass-specific method.