본문 바로가기
코틀린 문법

9. 상속, 오버라이딩과 추상화

by 농농씨 2023. 4. 30.

코드테스트 사이트:play.kotlinlang.org

참조:유튜브 디모의 코틀린

 

상속

fun main() {

//상속

//필요한 경우

//1.이미 존재하는 클래스를 확장하여 새로운 속성이나 새로운 클래스 만들기

//2.여러개의 클래스 만들었는데 클래스끼리 공통점 뽑아 코드관리 용이하게

//속성,함수 물려주면 수퍼클래스, 물려받으면 서브클래스

//애완동물 관리하는 클래스 만들어보기

 

var a = Animal("별이",5,"개")//animal 클래스에 속성 다 기입함

var b = Dog("별이",5)//dog 클래스에 종 빼고 속성 기입함

//->둘다 같은 속성과 기능을 갖게 됨

 

a.introduce()//자기소개함수 호출

b.introduce() //a인스턴스와 b인스턴스의 함수호출결과가 동일함

 

}

open class Animal//open:클래스가 상속되게 클래스 선언 시 붙여줄 수 있는 키워드

//코틀린은 상속 금지가 기본값이라서 open상태 되어야만 상속가능

(var name:String, var age:Int, var type:String) //이름,나이,종류 정보

{

fun introduce(){ //동물 정보 추가하는 함수 만듦

println("저는 ${type} ${name}이고, ${age}살 입니다.")

//println함수에서 클래스 호출할때 달러표시랑 중괄호로 표시

//클래스 자신의 속성임이 확실할 때는 this.type 이런 식으로 안해도 됨

}

}

//상속규칙

//1.서브클래스는 수퍼클래스에 존재하는 속성과 '같은이름'의 속성 가질수 없음

//2.서브클래스 생성될 때 반드시 수퍼클래스의 생성자까지 호출되어야 함(?)

class Dog (name:String, age:Int):Animal(name,age,"개")

//상속하는 법:서브클래스 선언뒤 콜론 붙이고 수퍼클래스의 생성자 호출할수있게함

//생성된 패러미터의 이름,나이,"개"라는 종류는 공통된 값이므로 고정으로 넘김

//var,val등을 붙이면 속성으로 선언됨

//생성자에서 이름과 나이를 받긴 하지만, 클래스의 자체 속성으로 만들어주는

//var을 붙이진 말고!! 일반 패러미터로 받아 animal 클래스의 생성자에 넘겨줌

~주석 너무 많아서 주석 지우고~

dog만의 함수랑 cat class 새로 만들어보기

fun main() {

 

var a = Animal("별이",5,"개")

var b = Dog("별이",5)

 

a.introduce()

b.introduce()

 

b.bark()

 

var c = Cat("루이", 1) //cat클래스에 있는 새로운 인스턴스

 

c.introduce() //animal 클래스에 있는 자기소개 함수 호출

c.meow() //cat클래스만의 함수 호출돼서 야옹야옹 함

 

}

open class Animal

(var name:String, var age:Int, var type:String) //이름,나이,종류 정보

{

fun introduce(){ //동물 정보 추가하는 함수 만듦

println("저는 ${type} ${name}이고, ${age}살 입니다.")

 

}

}

class Dog (name:String, age:Int):Animal(name,age,"개")

//dog만의 함수를 추가해줄순 없을까?

{

fun bark(){

println("멍멍")

}

}

class Cat (name:String, age:Int) : Animal(name,age,"고양이")//새로운서브클

{

fun meow(){//cat 클래스만의 함수

println("야옹야옹")

}

}

//클래스의 상속은 클래스를 더욱 구조적으로 다룰 수 있게 해준다!

//하지만 지나친 상속구조는 코드를 어렵게 한다~

오버라이딩과 추상화

fun main() {

//오버라이딩

//기본적으로 수퍼클래스와 같은이름,같은형태의 함수는 서브클래스에서 쓸수없음

//하지만 수퍼클래스에서 허용하면 가능함

var t = Tiger()//tiger클래스의 새로운 인스턴스

t.eat()//(서브클래스인)tiger 클래스의 인스턴스로 수퍼클래스 함수 호출함

//근데 수퍼클래스의 함수를 open시켜서 서브클래스에서 오버라이딩

//으로 함수를 재구현해서 "고기를 먹습니다 출력됨"

}

open class Animal {//상속할 수 있는 오픈된 클래스 만들고

open fun eat() {//eat함수 생성 //수퍼클래스에서 open 붙은 함수는

//서브클래스에서 override 붙여서 재구현 가능!

println("음식을 먹습니다")

}

}

class Tiger : Animal(){ //상속받는 클래스

override fun eat(){

println("고기를 먹습니다")

}

}

추상화

fun main() {

//추상화:수퍼클래스에 함수 구체적 내용없이 모든 서브클래스에 공통적인

//어떠한 함수가 있다는 점만 명시 (=/=오버라이딩)

//추상화:추상함수+추상클래스로 구성됨

//추상함수:선언부만 있고 기능은 구현되지 않음

//추상클래스:추상함수 포함함

var r = Rabbit()//rabbit 클래스의 인스턴스 생성

 

r.eat()//수퍼클래스에선 abstract고 실제 동작은 서브클래스에 있는 함수

r.sniff()//수퍼클래스에 있으면서 abstract 아닌 함수

}

abstract class Animal { //animal 클래스에 abstract 붙임

abstract fun eat() //내부의 추상함수에도 abstract붙이고 내용 없음

fun sniff(){

println("킁킁")

}

}//추상함수는 빈껍데기=>추상클래스 단독으로 인스턴스 만들수없음!!!!

//따라서 반드시 서브클래스에서 상속받아 abstract표시된 함수들을 구현해줘야 함

//(abstract는 상속이 필수인건가)

class Rabbit : Animal(){//animal 클래스 상속받는 서브클래스 생성

override fun eat(){//override 키워드 붙여야하는거 잊지말기!

//eat이라는 추상함수의 실제 동작이 되는 구현부

println("당근을 먹습니다")

}

}

인터페이스

:또다른 추상화 방법

 

fun main() {

//코틀린에서 인터페이스는 속성,추상함수,일반함수 모두 가질수있음

//단, 추상함수는 생성자를 가질 수 있는 반면 인터페이스는 생성자 못가져

//인터페이스에서

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

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

//따라서 open이나 abstract같은 별도의 키워드 없이도

//포함된 모든 함수를 서브클래스에서 구현 및 재정의 할 수 있음!

//또한 한번에 여러인터페이스를 상속받을수있음

//ex. 서브클래스 하나가 인터페 A랑 인터페B 둘다 상속받을수있음

//따라서 좀더 유연한 설계가 가능함

 

//인터페이스 2개 한번에 상속받는 클래스 만들어보자~

var d=Dog()

 

d.run()//인터페이스 runner의 구현부 없던 함수를 상속받아 재구현한 함수

d.eat()//인터페이스 eater의 구현부 있던 함수를 상속받아 재구현한 함수

//결과적으로 Dog 클래스는 두 인터페이스를 상속받음

//!!주의!! 여러개 상속받을때는 서브클래스에서 꼭 오버라이딩으로 재구현해주기

 

}

interface Runner{//open 같은 키워드 필요없는, 인터페이스 생성

fun run()//abstract같은 키워드 안붙이고도 구현부 없는 함수 생성

}

interface Eater{

fun eat(){

println("음식을 먹습니다.")

}

}

class Dog : Runner, Eater(){//클래스가 두 인터페이스 동시에 상속받으려면

//클래스 선언 뒤에 콜론 붙이고 뒤에 인터페이스 이름 쉼표로 구분해주기~

override fun run() {//인터페이스 내부에서는 키워드 필요 없지만

//상속받는 클래스는 (구현부 없던) 함수에 override 키워드 써야함!

println("우다다다 뜁니다")

}

override fun eat(){ //구현부 있던 함수도 override 붙여주고~

println("허겁지겁 먹습니다")//재구현~

 

}

}

//정리

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

//추상화:형식만 선언하고 실제 구현은 서브클래스에 일임할 때

//인터페이스:서로 다른 기능들을 여러개 물려주어야 할 때!

//유용하다~

참고:유튜브 디모의 Kotlin 강좌