Abstract Classes

An abstract class has the abstract keyword:

abstract class Animal {
  abstract fun hasGills(): Boolean
}

An abstract class is automatically open as well — we do not need the open keyword to be able to create subclasses.

As with Java, we cannot create instances of an abstract class. If we try to do so:

abstract class Animal {
  abstract fun hasGills(): Boolean
}

val critter = Animal()

…we fail with a compile error:

error: cannot create an instance of an abstract class
val critter = Animal()
              ^

Abstract Members

We can then start defining members of the class that also have the abstract keyword. Mostly, that will be abstract functions:

abstract class Animal {
  abstract fun hasGills(): Boolean
}

An abstract class can have ordinary functions as well — you are not limited to just ones with the abstract keyword. Ordinary functions can themselves be open or not, as you see fit:

abstract class Animal {
  abstract fun hasGills(): Boolean

  open fun displayName(): String = "Animal"

  fun description() = "${displayName()}: hasGills = ${hasGills()}"
}

It is also possible to create abstract properties, though we will hold off on this until much later in the book.

Concrete and Abstract Subclasses

A subclass of an abstract class either:

So, for example, this does not work:

abstract class Animal {
  abstract fun hasGills(): Boolean

  fun description() = "${displayName()}: hasGills = ${hasGills()}"
}

class Frog : Animal()

class Axolotl : Animal()

class KomodoDragon : Animal()

We get a compile error for each of the Animal subclasses:

 error: class 'Frog' is not abstract and does not implement abstract base class member public abstract fun hasGills(): Boolean defined in Test.Animal
class Frog : Animal()
^

Since hasGills() is abstract, the subclasses need to be either abstract or provide an implementation for hasGills():

abstract class Animal {
  abstract fun hasGills(): Boolean

  fun description() = "hasGills = ${hasGills()}"
}

class Frog(val hasGillsRightNow: Boolean) : Animal() {
  override fun hasGills() = hasGillsRightNow
}

class Axolotl : Animal() {
  override fun hasGills() = true
}

class KomodoDragon : Animal() {
  override fun hasGills() = false
}

fun main() {
  println(Axolotl().description())
  println(KomodoDragon().description())
  println(Frog(true).description())
}

Exactly how the subclass implements hasGills() is up to that subclass. Axolotl and KomodoDragon have hard-coded responses, while Frog has its hasGills() depend upon a constructor parameter.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.