Menu
Coddy logo textTech

Sobrescrevendo Membros

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 18 de 57.

Uma subclasse pode substituir um método herdado pela sua própria versão. A superclasse marca o método como open, e a subclasse o declara novamente com override:

open class Animal(val name: String) {
    open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
    override fun sound() = "Meow"
}

Dentro de main:

println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())

Saída:

Woof
Meow
...

A versão que é executada é escolhida pela classe real do objeto, mesmo quando o tipo da variável é a superclasse. O código dentro da superclasse que chama um método aberto também obtém a versão da subclasse:

open class Animal(val name: String) {
    open fun sound() = "..."
    fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}

Dentro de main:

val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())

Saída:

Rex says Woof
Generic says ...

As propriedades podem ser sobrescritas da mesma forma: open val na superclasse, override val na subclasse, seja como uma propriedade normal, uma propriedade do construtor ou um getter computado:

open class Shape {
    open val name = "shape"
    open val corners = 0
}
class Triangle : Shape() {
    override val name = "triangle"
    override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
    override val name: String
        get() = "$corners-gon"
}

Dentro de main:

for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")

Saída:

shape: 0
triangle: 3
6-gon: 6

Um membro marcado como override é aberto novamente, portanto uma subclasse da subclasse pode substituí-lo mais uma vez; final override impede isso. Um membro sem open não pode ser substituído de forma alguma, e uma subclasse não pode declarar um membro com a mesma assinatura:

open class Animal {
    open fun sound() = "..."
    fun sleep() = "zzz"
}
open class Dog : Animal() {
    final override fun sound() = "Woof"
}
class Puppy : Dog() {
    // override fun sound() = "Yip"   // erro: 'sound' em 'Dog' é final
    // fun sleep() = "nap"            // erro: 'sleep' oculta um membro da superclasse
}
challenge icon

Desafio

Fácil

Animal tem legs() (4), sound() (...) e describe(), que retorna Rex has 4 legs and says Woof, construído a partir de legs() e sound(). Torne legs() e sound() sobrescritos e complete as subclasses sobrescrevendo apenas esses dois métodos: Dog diz Woof, Bird tem 2 pernas e diz Tweet, e Snake tem 0 pernas e diz Hiss. describe() permanece como está em Animal.

O código fornecido lê linhas dog,Rex, bird,Pip, snake,Kaa ou qualquer outro tipo (um Animal simples), armazena os animais em uma única List<Animal> e imprime describe() para cada um.

Seu código deve ficar em Animal.kt, Dog.kt, Bird.kt e Snake.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o como está
    val input = generateSequence(::readLine).toList()
    val animals = mutableListOf<Animal>()
    for (line in input) {
        val (kind, name) = line.split(",")
        animals.add(when (kind) {
            "dog" -> Dog(name)
            "bird" -> Bird(name)
            "snake" -> Snake(name)
            else -> Animal(name)
        })
    }
    for (a in animals) println(a.describe())
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin