Menu
Coddy logo textTech

Abstract Classes

Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 20 of 57.

An abstract class is a superclass that cannot be instantiated on its own. It can declare abstract members without a body, and every concrete subclass must implement them:

abstract class Shape(val name: String) {
    abstract fun area(): Double

    fun describe() = "$name with area ${area()}"
}
class Circle(val r: Double) : Shape("circle") {
    override fun area() = 3.14 * r * r
}
class Rect(val w: Double, val h: Double) : Shape("rect") {
    override fun area() = w * h
}

Inside main:

val shapes: List<Shape> = listOf(Circle(1.0), Rect(2.0, 3.0))
for (s in shapes) println(s.describe())

Output:

circle with area 3.14
rect with area 6.0

An abstract class is open without the keyword, and its abstract members are open too, so subclasses only write override. Creating the abstract class itself does not compile, and a subclass that leaves an abstract member out must be abstract as well. Use an abstract class when the superclass has no sensible behaviour of its own for some members:

// val s = Shape("blob")                       // error: cannot create an instance of an abstract class
// class Blob : Shape("blob")                  // error: Blob does not implement area()
abstract class Polygon(name: String) : Shape(name)   // fine: still abstract

An abstract class can have a constructor, state and normal methods, which subclasses inherit. A common use is a fixed procedure whose steps vary, the template method: the superclass method runs the steps, and subclasses fill in the abstract ones:

abstract class Report(val title: String) {
    fun render() = "== $title ==\n${body()}\n(${footer()})"

    abstract fun body(): String
    open fun footer() = "end"
}
class Sales(val total: Int) : Report("Sales") {
    override fun body() = "total: $total"
}
class Stock(val items: Int) : Report("Stock") {
    override fun body() = "items: $items"
    override fun footer() = "counted today"
}

Inside main:

println(Sales(420).render())
println(Stock(17).render())

Output:

== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)

Abstract properties work the same way. The subclass supplies the value as a constructor property, a stored property or a getter:

abstract class Worker(val name: String) {
    abstract val monthly: Int
    fun yearly() = monthly * 12
}
class Salaried(name: String, override val monthly: Int) : Worker(name)
class Hourly(name: String, val hours: Int, val rate: Int) : Worker(name) {
    override val monthly: Int
        get() = hours * rate
}

Inside main:

val staff = listOf(Salaried("Ada", 4000), Hourly("Bo", 80, 25))
for (w in staff) println("${w.name}: ${w.yearly()}")

Output:

Ada: 48000
Bo: 24000
challenge icon

Challenge

Easy

Discount is an abstract class. It declares the abstract method amount(price) and implements apply(price), which returns the price minus amount(price) but never below 0. Complete the subclasses: PercentOff(percent) takes that percentage of the price (rounded down), FixedOff(value) takes a fixed value, and SpendMore(threshold, off) takes off only when the price is at least threshold.

The supplied code reads the price and then discounts p,10, f,300 or s,500,50, applies each to the price and prints 1000 -> 900.

Your code goes in Discount.kt, PercentOff.kt, FixedOff.kt and SpendMore.kt. Main.kt holds the supplied input/output code and cannot be edited.

Try it yourself

fun main() {
    // Supplied input/output code: keep it as it is
    val input = generateSequence(::readLine).toList()
    val price = input[0].toInt()
    for (line in input.drop(1)) {
        val p = line.split(",")
        val discount: Discount = when (p[0]) {
            "p" -> PercentOff(p[1].toInt())
            "f" -> FixedOff(p[1].toInt())
            else -> SpendMore(p[1].toInt(), p[2].toInt())
        }
        println("$price -> ${discount.apply(price)}")
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Kotlin playground