• [코틀린/Kotlin] 오버라이딩과 추상화

    2021. 11. 3.

    by. 하루플스토리

    반응형

    https://www.youtube.com/watch?v=8RIsukgeUVw&list=PLQdnHjXZyYadiw5aV3p6DwUdXV2bZuhlN&index=2 
    저는 위 강의를 보면서 개인적으로 공부한 내용을 정리하였습니다. 


    오버라이딩 Overriding

     

    상속시에는 기본적으로 수퍼클래스에 있는 함수와 같은 이름과 형태를 가진 함수는 서브클래스에서는 만들 수 없다.

    하지만 수퍼클래스에서 허용만 한다면 오버라이딩이라는 방법으로 서브클래스에서 같은 이름과 형태로 된 함수의 내용을 다시 구현할 수 있다.

    fun main() {
    	var t = Tiger()
        t.eat()
    }
    
    open class Animal {
        fun eat() {
            println("음식을 먹습니다")
        }
    }
    
    class Tiger : Animal()

    실행결과 : 음식을 먹습니다

     

    만약 Tiger 클래스에서 "고기를 먹습니다" 라고 출력하고 싶어도 이미 eat 함수는 Animal에서 "음식을 먹습니다" 라고 구현되어 있기 때문에 서브클래스에서는 함수를 재구현할 수 없다.

     

    이 때, Animal클래스에서 eat 함수 앞에 open이 붙어있었다면 Tiger에서 재구현이 허용된다.

    서브클래스에서 override를 붙여 재구현 하면 된다.

    fun main() {
    	var t = Tiger()
        t.eat()
    }
    
    open class Animal {
        open fun eat() { //override를 위해 open 함.
            println("음식을 먹습니다")
        }
    }
    
    class Tiger : Animal(){
        override fun eat(){ //override 함.
            println("고기를 먹습니다")
        }
    }

    실행결과 : 고기를 먹습니다

     

     

     

     

    추상화 abstraction

    이번엔 오버라이딩과 다르게 수퍼클래스에서는 함수의 구체적인 구현은 없고, 단지 Animal의 모든 서브클래스는 eat이라는 함수가 '반드시 있어야 한다'는 점만 명시하여 각 서브클래스가 비어있는 함수의 내용을 필요에 따라 구현하도록 하려면 추상화라는 개념을 사용한다.

    추상화는 선언부만 있고 기능이 구현되지 않은 추상함수, 추상 함수를 포함하는 추상 클래스라는 요소로 구성된다.

    *추상함수는 비어있는 껍데기라고 생각하면 된다.

    fun main() {
    
    }
    
    abstract class Animal {
        abstract fun eat()
        fun sniff(){
            println("킁킁")
        }
    }

    이렇게 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("당근을 먹습니다")
        }
    }

    Rabbit의 인스턴스를 만들어 eat과 sniff를 수행하도록 하면 된다.

    실행결과

    당근을 먹습니다
    킁킁

     

     

    추상화를 하는 또 다른 방법이 있다.

    인터페이스 라는 기능이다. 다른 언어에서 원래 인터페이스는 추상 함수로만 이루어져 있는 '순수 추상화 기능'을 말하는 것이라고 알건데 코틀린에서는 인터페이스 역시 추상함수와 일반 함수를 모두 가질 수 있다.

    다만 추상함수는 생성자를 가질 수 있는 반면, 인터페이스는 생성자를 가질 수는 없으며 인터페이스에서

    구현부가 있는 함수 -> open 함수로 간주

    구현부가 없는 함수 -> abstract 함수로 간주

     

    그래서 별도의 키워드가 없어도 포함된 모든 함수를 서브클래스에서 구현 및 재정의가 가능하다.

    또한, 한번에 여러 인터페이스를 상속 받을 수 있으므로 좀 더 유연한 설계가 가능하다.

     

    fun main() {
    	//Dog는 두 인터페이스의 형식을 모두 물려받아 사용하는 서브클래스가 됨.
        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("허겁지겁 먹습니다")
        }
    }

    실행결과

    우다다다 뜁니다
    허겁지겁 먹습니다

     

    한자기 주의해야 할 점은 여러개의 인터페이스나 클래스에서 같은 이름과 형태를 가진 함수를 구현하고 있다면 서브클래스에서는 혼선이 일어나지 않도록 반드시 오버라이딩하여 재구현 해주어야 한다.

     

     

     

    오버라이딩은 이미 구현이 끝난 함수의 기능을 서브클래스에서 변경해야 할 때 사용

     

     

    추상화는 형식만 선언하고 실제 구현은 서브클래스에 일임할때 사용하는 기능

     

     

    인터페이스는 서로 다른 기능들을 여러개 물려주어야 할 때 유용한 기능
    반응형

    댓글