티스토리 뷰

728x90

 


상속(Inheritance)

• 상속이 필요한 경우

     - 바탕이 되는 클래스에 확장이 되는 클래스를 만들고 싶은 경우

     - 이미 존재하는 클래스를 합칠 때

• open 키워드로 설정된 클래스만 상속할 수 있다.

     ex) open class 클래스명() {}

• final 키워드로 설정된 클래스는 상속할 수 없다.

     - 명시하지 않는다면 기본적으로 final로 선언.

     ex) final class 클래스명() {}

• 상속해준 클래스를 슈퍼 클래스(또는 부모 클래스), 상속받은 클래스를 서브 클래스(또는 자식 클래스)라고 한다.

• 서브 클래스는 슈퍼 클래스가 가지고 있는 모든 것을 물려 받는다.

// 상속을 사용하지 않을 때 - 같은 코드 반복 및 클래스끼리의 연관성 확인 어려움.
class Warrior() {
    fun attack() {
        println("복잡한 코드 + 공격")
    }
}
class DefenseWarrior() {
    fun attack() {
        println("복잡한 코드 + 공격")
    }

    fun defense() {
        println("방어")
    }
}
class HardAttackWarrior() {
    fun attack() {
        println("복잡한 코드 + 공격")
    }

    fun hardAttack() {
        println("강하게 공격")
    }
}

// 상속을 사용할 경우 - 공통된 코드 공유, 클래스끼리 연관성 명시
open class Warrior2(var name: String, var power: Int, var type: String) { // 슈퍼 클래스(부모 클래스)
    fun attack() {
        println("복잡한 코드 + 공격")
    }
}
class DefenseWarrior2(name: String, power: Int) : Warrior2(name, power, "골렘") { // 서브 클래스(자식 클래스)
    fun defense() {
        println("방어")
    }
}
val defenseWarrior2: DefenseWarrior2 = DefenseWarrior2("단단한 골렘", 100)
defenseWarrior2.attack() // defenseWarrior2는 DefenseWarrior2의 인스턴스지만 Warrior2의 메소드 attack()을 상속받았기 때문에 사용할 수 있다.
defenseWarrior2.defense() // defenseWarrior2의 메소드 defense() 사용 가능

• 서브 클래스는 슈퍼 클래스의 생성을 책임져야 한다.

open class Warrior2(var name: String, var power: Int, var type: String) {
    fun attack() {
        println("복잡한 코드 + 공격")
    }
}

// 서브 클래스의 주 생성자가 슈퍼 클래스의 생성을 책임지는 경우
class DefenseWarrior2(name: String, power: Int) : Warrior2(name, power, "골렘") { 주 생성자가 슈퍼 클래스 생성
    fun defense() {
        println("방어")
    }
}

// 서브 클래스의 부 생성자가 슈퍼 클래스의 생성을 책임지는 경우
class HardAttackWarrior2 : Warrior2 {
    var bonusPower: Int = 0

    // 부 생성자가 슈퍼 클래스 생성
    constructor(name: String, power: Int, bonusPower: Int) : super(name, power, "오크") { // super는 슈퍼 클래스(부모 클래스)를 의미한다.
        this.bonusPower = bonusPower
    }

    fun hardAttack() {
        println("강하게 공격")
    }
}

• 서브 클래스는 슈퍼 클래스가 사용하고 있는 멤버와 동일한 이름의 멤버를 만들 수 없다.

class WizardWarrior(var name: String, var power: Int) : Warrior2(name, power, "고블린"), Warrior() { // 오류 발생 : 슈퍼 클래스에서 사용하고 있는 name, power를 다시 var로 선언할 수 없다.
    fun attack() { // 오류 발생 : 슈퍼 클래스에서 사용하고 있는 attack()을 다시 선언할 수 없다.
        println("복잡한 코드 + 공격")
    }

    fun magicAttack() {
        println("마법 공격")
    }
}

• 상속은 여러 번 할 수 있다. (A --상속--> B, B --상속--> C)

• 다중 상속은 불가능하다. (A, B를 상속하는 클래스 C)

class WizardWarrior2(name: String, power: Int) : Warrior2(name, power, "고블린"), Warrior() { // 오류 발생 : Warrior2와 Warrior 다중 상속 불가능
    fun magicAttack() {
        println("마법 공격")
    }
}

 

오버라이딩(Overriding)

• 기본적으로는 슈퍼 클래스가 사용하고 있는 멤버와 동일한 이름의 멤버를 만들 수 없다.

• 오버라이딩을 통해 슈퍼 클래스가 가지고 있는 함수를 재정의할 수 있다.

     * 재정의

          - 재선언

          - 이전에 정의한 것을 덮어쓴다. (이전에 정의한 것은 작동하지 않는다.)

• 함수 선언 맨 앞에 override 키워드를 적어준다.

open class Warrior3(var name: String, var power: Int, var type: String) {
    open fun attack() {
        println("복잡한 코드 + 공격")
    }
}

class WizardWarrior3(name: String, power: Int) : Warrior3(name, power, "고블린") {
    override fun attack() {
        super.attack() // 슈퍼 클래스의 attack 함수
        println("마법사라 지팡이로 때리는건 약하다")
    }

    fun magicAttack() {
        println("마법 공격")
    }
}
val wizardWarrior3 : WizardWarrior3 = WizardWarrior3("똑똑한 고블린", 50)
wizardWarrior3.attack() // 서브 클래스인 WizardWarrior3에서 정의한 attack() 메소드가 실행된다.

 

 

 

 

 

 

 

이 글은

패스트 캠퍼스 Android 앱 개발의 정석 with Kotlin 올인원 패키지 Online

강의를 듣고 공부한 내용을 바탕으로 작성되었습니다.

 


728x90
댓글
250x250
공지사항