Kotlin classes and members are final by default. Mark a class open to allow subclasses, and each replaceable member open too; the subclass must then write override. An interface declares abstract members and may carry default bodies, but no stored state. A class extends one class and any number of interfaces, after one colon.
interface Priced {
val price: Double
fun label(): String = "$%.2f".format(price) // default method
}
open class Product(val title: String, override val price: Double) : Priced {
open fun describe() = "$title, ${label()}"
}
class EBook(title: String, price: Double, val sizeMb: Int) : Product(title, price) {
override fun describe() = super.describe() + " (EPUB, $sizeMb MB)"
override fun label() = "$%.2f download".format(price)
}
fun main() {
println(Product("Salt and Saffron", 24.00).describe())
println(EBook("Patterns of the Deep Web", 39.50, 12).describe())
}Salt and Saffron, $24.00 Patterns of the Deep Web, $39.50 download (EPUB, 12 MB)
Product(title, price) calls the superclass constructor, and dispatch is virtual: super.describe() calls the EBook override of label(). Without open, class SignedBook(title: String) : Book(title) fails with this type is final, so it cannot be extended.

Use an abstract class when subtypes share state, an interface when they share only a contract, and a sealed type (Sealed and Enum Classes) when the compiler should know every subtype.