언어(Programming Language)/Kotlin

[Kotlin] 클래스 상속 사용법

RyanSin 2021. 2. 18. 16:20
반응형

- 지난 시간

안녕하세요. 지난 시간에는 Function에 대해 알아봤습니다.

 

Kotlin Class와 Kotlin Function에 대해 잘 이해하지 못하셨다면, 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다. :)

 

Kotlin Class: any-ting.tistory.com/59

 

[Kotlin] 클래스(Class) 생성자(Constructors) 개념 및 사용법

- 개요 안녕하세요. 이번 시간에는 객체지향 프로그램에서 제일 어려운 개념인... Class(클래스)에 대해 알아보겠습니다. 일단 Class란 무엇일까요?? 딱 머릿속에 생각나는 게 없네요... 등급인가?...

any-ting.tistory.com

Kotlin Function: any-ting.tistory.com/60

 

[Kotlin] 함수(Function) 사용법

- 지난 시간 안녕하세요. 지난 시간에는 Kotlin의 클래스와 생성자에 대해 알아봤습니다. 혹시 놓치고 오신 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다. any-ting.tistory.com/59 [Kotl

any-ting.tistory.com

- 개요

객체지향 언어에서는 클래스 설계가 정말 가장 중요합니다.

필요한 데이터와 불 필요한 데이터를 확실하게 정하고 그걸 토대로 하나의 프로그램이 완성되기 때문입니다.

 

이번 시간에 우리는 클래스 간에 상속에 대해 알아보겠습니다.

 

코틀린에서는 상위 형식은 Any입니다. 자바에서는 Object 형식과 동일하며, 모든 코틀린 클래스는 명시적 또는 암시적으로 Any 클래스를 상속받습니다.

 

class Person // 암시적 Any 상속
class Person : Any // 명시적 Any 상속

 

상속이란 무엇일까요?? 상속은 말 그대로 "부모로부터 자식에게 무언가를 물려주는 것"입니다. 

부모 => 자식 상속

보통 우리는 부모님께 성(이름), 성향, 얼굴형, 유전자 등등 여러 가지를 물려받습니다.

 

예시로 우리가 보통 게임을 하면 초보자로 시작해서 직업을 선택해서 등급이 올라갑니다.

 

위 그림과 같은 구조일 거예요. (제가 게임을 안 해서... 직업이 생각이...)

 

보통 초보자 때는 일반 공격만 가능하다가, 전직을 하면 이제 스킬을 사용할 수 있게 되죠?

 

전사와 마법사는 스킬은 다르지만 기본 일반 공격은 공통입니다. 이러한 상황에서는 초보자는 전사 마법사에게 기능을 상속해주면 됩니다.

 

코드로 만들어 보겠습니다.

 

- 초보자 클래스

package main

/**
 * 코틀린에서는 open 한정자를 사용해서 상속을 허용한다.
 */

//초보자 클래스
open class Beginner(
    var name: String, //이름 
    var hp: Int, //체력
    var mp: Int, //마나
    var experience: Int //경험치
) {
    //일반 공격
    open fun attack(monster: Monster) {
        monster.hp -= 10 // 몬스터에게 10에 데미지를 입힌다.
    }
}

코틀린에서는 open 한정자를 사용해서 상속을 허용합니다.

 

속성과, 함수 또한 open 한정자를 선언해야 자식 클래스가 참조해 사용할 수 있습니다.

 

- 전사 클래스

package main

/**
 * 파라미터 값에 지정한 속성들을 부모(Beginner) 클래스에게 위임한다.
 */
//전사 클래스 생성
open class Soldier (name: String, hp: Int, mp: Int, experience: Int) : Beginner(name, hp, mp, experience){

    // 전사 일반 공격
    override fun attack(monster: Monster) {
        /**
         * 느낌표 두 개(!!)는 Null 값 보증 연산자이다.
         * monster 변수는 절대 Null 값일 수 없다는 뜻 이다. Null 값이 들어오면 에러가 발생한다.
         */
        super.attack(monster!!)
    }

}

 

open 한정자를 사용해 허용한 소스코드는 override를 사용해서 재 정의할 수 있습니다.

super 키워드는 자바와 동일한 기능을 제공합니다. :)

 

- 몬스터 클래스

package main

// 몬스터 클래스
class Monster(
    var name: String, //이름
    var hp: Int, //체력
    var mp: Int, //마나
    var experience: Int //경험치
) {
    //일반 공격
    fun attack(beginner: Beginner) {
        beginner.hp -= 10 // 캐릭터에게 10에 데미지를 입힌다,
    }
}

초보자 클래스와 전사 클래스 그리고 몬스터 클래스를 만들었습니다.

 

그리고 아래와 같이 전사 클래스와 몬스터 클래스를 생성했습니다.

fun main() {

    //전사 클래스 생성! (자식 클래스)
    val soldier = Soldier("개발이 취미인 사람", 100, 100, 0)

    println("전사 클래스 정보")
    println(soldier.name)
    println(soldier.hp)
    println(soldier.mp)
    println(soldier.experience)

    println()
    println("-----------------------------")
    println()

    //몬스터 클래스 생성!
    val monster = Monster("초록 달팽이", 10, 0, 10)

    println("몬스터 클래스 정보")
    println(monster.name)
    println(monster.hp)
    println(monster.mp)
    println(monster.experience)

    /**
     * 실행 결과
     *
     * 전사 클래스 정보
     * 개발이 취미인 사람
     * 100
     * 100
     * 0
     *
     * -----------------------------
     * 
     * 몬스터 클래스 정보
     * 초록 달팽이
     * 10
     * 0
     * 10
     */

}

전사 클래스는 초보자 클래스를 상속받고 속성들을 위임했습니다. (사실 이 부분은 상속을 받기 위해 사용된 속성입니다.)

 

기본 생성자 앞에 var & val 키워드를 사용해서 선언하지 않았기 때문에 해당 속성은 초보자 클래스가 사용됩니다.

 

이번에는 super 키워드를 통해 사용된 함수를 사용해 보겠습니다.

 

fun main() {

    //전사 클래스 생성! (자식 클래스)
    val soldier = Soldier("개발이 취미인 사람", 100, 100, 0)

    println("전사 클래스 정보")
    println(soldier.name)
    println(soldier.hp)
    println(soldier.mp)
    println(soldier.experience)

    println()
    println("-----------------------------")
    println()

    //몬스터 클래스 생성!
    val monster = Monster("초록 달팽이", 10, 0, 10)

    println("몬스터 클래스 정보")
    println(monster.name)
    println(monster.hp)
    println(monster.mp)
    println(monster.experience)

    println()
    println("-----------------------------")

    println("몬스터 공격")
    soldier.attack(monster)

    println("몬스터 클래스 정보")
    println(monster.name)
    println(monster.hp)
    println(monster.mp)
    println(monster.experience)

    /**
     * 실행 결과
     *
     * 전사 클래스 정보
     * 개발이 취미인 사람
     * 100
     * 100
     * 0
     *
     * -----------------------------
     *
     * 몬스터 클래스 정보
     * 초록 달팽이
     * 10
     * 0
     * 10
     * 
     * -----------------------------
     * 몬스터 공격
     * 몬스터 클래스 정보
     * 초록 달팽이
     * 0
     * 0
     * 10
     */
}

몬스터 체력이 0으로 변경 됐습니다.

 

전사 클래스에서 함수의 기능을 재 정의하지 않고 부모의 기능을 그대로 사용하고 있습니다.

 

- 응용 (이중 상속)

초보자 => 전사 => 검 전사

 

package main

/**
 * 코틀린에서는 open 한정자를 사용해서 상속을 허용한다.
 */

//초보자 클래스
open class Beginner(
    var name: String, //이름
    var hp: Int, //체력
    var mp: Int, //마나
    var experience: Int //경험치
) {
    //일반 공격
    open fun attack(monster: Monster) {
        monster.hp -= 10 // 몬스터에게 10에 데미지를 입힌다.
    }
}

package main

/**
 * 파라미터 값에 지정한 속성들을 부모(Beginner) 클래스에게 위임한다.
 */
//전사 클래스 생성
open class Soldier (name: String, hp: Int, mp: Int, experience: Int) : Beginner(name, hp, mp, experience){

    // 전사 일반 공격
    override fun attack(monster: Monster) {
        /**
         * 느낌표 두 개(!!)는 Null 값 보증 연산자이다.
         * monster 변수는 절대 Null 값일 수 없다는 뜻 이다. Null 값이 들어오면 에러가 발생한다.
         */
        super.attack(monster!!)
    }

    //파워스트라이크 (마법 공격)
    open fun powerStrike(monster: Monster) {
        if (mp == 0) {
            println("마나가 부족합니다.")
            return
        }

        //전사의 마나를 소모한다.
        mp -= 10

        //몬스터 체력을 감소한다.
        monster.hp -= 20
    }

}

package main

/**
 * 파라미터 값에 지정한 속성들을 부모(Soldier) 클래스에게 위임한다.
 */
//검 전사 클래스
class SwordSoldier(name: String, hp: Int, mp: Int, experience: Int) :
    Soldier(name, hp, mp, experience) {

    /**
     * 느낌표 두 개(!!)는 Null 값 보증 연산자이다.
     * monster 변수는 절대 Null 값일 수 없다는 뜻 이다. Null 값이 들어오면 에러가 발생한다.
     */

    //초보자 일반 공격
    override fun attack(monster: Monster) {
        super.attack(monster!!)
    }

    //전사 마법 공격
    override fun powerStrike(monster: Monster) {
        super.powerStrike(monster!!)
    }
}

 

fun main() {

    //검 전사 클래스 생성!
    val swordSoldier = SwordSoldier("개발이 취미인 사람", 100, 100, 0)


    println("검 전사 클래스 정보")
    println(swordSoldier.name)
    println(swordSoldier.hp)
    println(swordSoldier.mp)
    println(swordSoldier.experience)

    println()
    println("-----------------------------")
    println()

    //몬스터 클래스 생성!
    val monster = Monster("초록 달팽이", 10, 0, 10)

    println("몬스터 클래스 정보")
    println(monster.name)
    println(monster.hp)
    println(monster.mp)
    println(monster.experience)

    println()
    println("-----------------------------")

    println("몬스터 공격")
    swordSoldier.powerStrike(monster)

    println("몬스터 클래스 정보")
    println(monster.name)
    println(monster.hp)
    println(monster.mp)
    println(monster.experience)

    /**
     * 실행 결과
     *
     * 전사 클래스 정보
     * 개발이 취미인 사람
     * 100
     * 100
     * 0
     *
     * -----------------------------
     *
     * 몬스터 클래스 정보
     * 초록 달팽이
     * 10
     * 0
     * 10
     *
     * -----------------------------
     * 몬스터 공격
     * 몬스터 클래스 정보
     * 초록 달팽이
     * -10
     * 0
     * 10
     */    
}

 

아까보다 몬스터 체력이 10 감소된 걸 확인할 수 있습니다.

 

이번 시간에는 자바 클래스 상속에 대해 알아봤습니다. 감사합니다.

 

모르시거나 헷갈리시는 분들은 댓글을 남겨주세요. :)