서브 클래스는 수퍼 클래스와 같은 이름과 같은 형태로 구성된 함수를 가질 수 없다.
fun main() {
var t = Tiger()
t.eat()
}
open class Animal {
fun eat() {
println("음식을 먹습니다.")
}
}
class Tiger: Animal() {
fun eat() {
println("고기를 먹습니다.")
}
}
eat은 수퍼 클래스 Animal에서 사용하고 있다는 에러가 발생한다. 그러나 오버라이딩을 통해서 서브 클래스에서 다시 구현할 수 있다.
fun main() {
var t = Tiger()
t.eat()
}
open class Animal{
fun eat() {
println("음식을 먹습니다.")
}
}
class Tiger : Animal()
// 결과
음식을 먹습니다.
fun main() {
var t = Tiger()
t.eat()
}
open class Animal{
open fun eat() {
println("음식을 먹습니다.")
}
}
class Tiger : Animal() {
override fun eat() {
println("고기를 먹습니다.")
}
}
// 결과
고기를 먹습니다.
수퍼클래스에서 open이 붙은 함수는 서브클래스에서 override를 붙여 재구현할 수 있다.
오버라이딩은 이미 수퍼클래스에서 구현이 끝난 함수를 서브클래스에서 재구현하는 것이다.
다음으로 배울 것은 수퍼클래스에서 함수의 구체적인 구현은 없고, 단지 수퍼클래스의 "모든 서브클래스는 해당 함수를 반드시 구현해야 한다." 것만 명시하여 각 서브클래스가 비어있는 함수의 내용을 필요에 따라 구현하도록 하는 방식인 추상화(abstraction)에 대해서 알아보자.
fun main() {
var r = Rabbit()
r.eat()
r.sniff()
}
abstract class Animal { // 추상클래스는 인스턴스를 만들 수 없다.
abstract fun eat() // 추상함수는 구현하지 않는다.
fun sniff() {
println("킁킁")
}
}
class Rabbit : Animal() {
override fun eat() {
println("당근을 먹습니다.")
}
}
추상화의 또 다른 방법인 인터페이스(Interface)를 알아보자.
fun main() {
var d = Dog()
d.run()
d.eat()
}
interface Runner {
fun run()
}
interface Eater {
fun eat() {
println("음식을 먹습니다.")
}
}
class Dog : Runner, Eater { // 두 인터페이스를 상속받으려면 표기만 해주면 된다.
override fun run() {
println("우다다다 뜁니다.")
}
override fun eat() {
println("허겁지겁 먹습니다.")
}
}
여러개의 인터페이스나 클래스에서 같은 이름과 형태를 가진 함수를 구현하고 있다면 서브클래스에서 혼선이 일어나지 않도록 오버라이딩해서 재구현해주어야 한다.
fun main() {
var p = Person()
p.breath()
}
interface Runner {
fun breath() {
println("숨을 하우하후 쉽니다.")
}
}
interface Eater {
fun breath() {
println("숨을 후하후하 쉽니다.")
}
}
class Person : Runner, Eater {
override fun breath() {
super<Eater>.breath()
super<Runner>.breath()
}
}