[Kotlin] 11. 오버라이딩과 추상화

오도원공육사·2021년 5월 25일
0

코틀린 기초문법

목록 보기
11/13


서브 클래스는 수퍼 클래스와 같은 이름과 같은 형태로 구성된 함수를 가질 수 없다.

fun main() {
    var t = Tiger()
    t.eat()
    
}

open class Animal {
    fun eat() {
        println("음식을 먹습니다.")
    }
}

class Tiger: Animal() {
    fun eat() {
        println("고기를 먹습니다.")
    }
}

eat은 수퍼 클래스 Animal에서 사용하고 있다는 에러가 발생한다. 그러나 오버라이딩을 통해서 서브 클래스에서 다시 구현할 수 있다.

1. 오버라이딩

1-1. 오버라이딩

  • 수퍼클래스에서 허용하면 서브클래스에서 같은 형태로된 함수를 만들 수 있다.
  • 즉, 수퍼클래스의 메서드를 서브클래스가 재정의 하는것.
  • open 키워드를 사용하면 오버라이딩이 가능하다.
  • 서브클래스에서 override 키워드를 이용하여 오버라이딩 할 수 있다.
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)에 대해서 알아보자.

2. 추상화 abstraction

  • 선언부만 있고, 기능이 구현되지 않은 추상함수(abstraction function)
  • 추상함수를 포함하는 추상클래스(abstraction class)
  • 추상화에는 위 두가지가 있다.

2-1. 추상함수, 추상클래스

  • 추상 클래스는 abstract 키워드를 사용한다.
    • 인스턴스를 만들 수 없다.
  • 추상 함수는 abstract 키워드를 사용한다.
    • 구현부를 적지않는다.
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)를 알아보자.

2-2. 인터페이스 (Interface)

  • 기존 고전 언어에서는 추상함수로만 이루어진 클래스를 말한다. → "순수 추상화 기능"
  • 그러나 코틀린에서는 속성, 추상함수, 일반함수 모두를 가질 수 있다.
  • 추상클래스는 생성자를 가질 수 있지만, 인터페이스는 생성자를 가질 수 없다.
  • interface 키워드를 사용해서 선언한다.

인터페이스에서의 함수

  • 구현부가 있는 함수 → open 함수로 간주
  • 구현부가 없는 함수 → abstract 함수로 간주
  • 따라서 별도의 키워드가 없어도 포함된 모든 함수를 서브클래스에서 구현 및 재정의 가능
  • 한번에 여러 인터페이스 상속(다중상속)으로 유연한 설계 가능

예시.

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()
    }
}
  • 수퍼클래스 이름을 꺾쇠 사이에 넣어서 super를 지정하면 어떤 타입의 메소드를 호출할지 지정할 수 있다.

정리

  • 오버라이딩
    • 이미 구현이 끝난 함수 기능을 서브 클래스에서 재정의(재구현, 변경)
  • 추상화
    • 형식만 선언하고 실제 구현은 서브클래스에 일임하는 것
  • 인터페이스
    • 서로 다른 기능들을 여러개 상속해줄 때 유용한 기능
profile
잘 먹고 잘살기

0개의 댓글

관련 채용 정보