Overriding Functions and Properties

open and override

Functions are also final by default. Mark a function open in the parent, then use override in the child. The override keyword is mandatory, so you never override by mistake.

Example

open class Shape(val name: String) {
    open fun area(): Double = 0.0
    fun describe() = println("$name has area %.2f".format(area()))
}

class Circle(val r: Double) : Shape("Circle") {
    override fun area() = Math.PI * r * r
}

class Square(val side: Double) : Shape("Square") {
    override fun area() = side * side
}

fun main() {
    Circle(2.0).describe()
    Square(3.0).describe()
}

Output

Circle has area 12.57
Square has area 9.00

Overriding Properties

Example

An open val can be overridden, even directly in the constructor.

open class Employee(val name: String) {
    open val baseSalary: Int = 30000
    open val role = "Employee"
}

class Manager(name: String) : Employee(name) {
    override val baseSalary = 80000
    override val role = "Manager"
}

class Intern(name: String, override val baseSalary: Int) : Employee(name) {
    override val role = "Intern"
}

fun main() {
    val team = listOf(Employee("Asha"), Manager("Vikram"), Intern("Rohit", 15000))
    for (e in team) println("${e.name} (${e.role}): ${e.baseSalary}")
}

Output

Asha (Employee): 30000
Vikram (Manager): 80000
Rohit (Intern): 15000

Tip: You may override a val with a var, but not a var with a val.

Stopping Further Overrides

An override member is itself open. Write final override to stop grandchildren from changing it.

open class Payment {
    open fun fee() = 0.0
}

open class CardPayment : Payment() {
    final override fun fee() = 1.5   // subclasses of CardPayment cannot override fee()
}