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:
- Needs to be abstract itself, or
- Needs to have implementations of all members defined as
abstract
that it inherited
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.