19. Inheritance and Overriding

Cavok·2020년 9월 28일
0

1. Inheritance

* 정의

- 클래스는 메서드나 프로퍼티 같은 멤버들을 다른 클래스로 부터 상속을 받아 접근하거나 호출할 수 있다. 사용자의 의도에 따라 기능을 추가하거나 재정의(Overriding) 하는 것도 가능하다.
  • 물려 주는 클래스 == Super-Class / Parents-Class
  • 물려 받는 클래스 == Sub-Class / Child-Class

class Cafe {
    var cafe1 = "IDIYA"
    var cafe2 = "HOLLYS"
}

class Coffee: Cafe { // 상속
    var Americano = "아메리카노"
    var Cappuccino = "카푸치노"
}


let c = Coffee() // 인스턴스 생성
만약 상속을 받고 싶다면 물려받는 클래스 이름 뒤에 콜론(:) 과 물려주는 클래스의 이름을 명시해주면 된다. 현재 Cafe 클래스는 상속받지 않는 Super-Class이다. 그러나 맡에 있는 Coffee 클래스는 Cafe 클래스를 상속 받고 있는 Sub-Class이다.
c.cafe1
c.cafe2
c.Americano
c.Cappuccino
현재 Coffee의 인스턴스를 생성하였다. Coffee인스턴스는 Cafe의 모든 멤버를 물려 받았기 때문에 보다시피 Coffee에서 Cafe의 저장속성인 cafe1, cafe2에 접근하는 것이 가능하다.

2. Overriding

* 정의

- Sub-Class에서는 Super-Class에서 물려받은(상속) 멤버를 변경하여 사용하는 것도 가능하다. 이것을 우리말로 재정의라고 한다. 재정의는 변경할 특성 앞에 override키워드를 명시하면 된다. 만약 변경된 멤버가 없는데 override키워드를 명시했다면 컴파일러는 오류를 일으킨다.
class Person {
    var name: String = ""   // 저장 프로퍼티
    var age: Int = 0  // 저장 프로퍼티
    var koreanAge: Int { //읽기전용 계산 프로퍼티
        return age + 1
    }
    
    var introduce: String { // 읽기전용 프로퍼티
        return "제 이름은 \(name)이고, 나이는 \(age)입니다."
    }
}

class Student: Person {
    var grade: String = "F" // 저장 프로퍼티
    override var introduce: String { // 재정의 
        return super.introduce + ",그리고 성적은 \(grade)입니다."
    }
    
    override var koreanAge: Int { // 재정의
        get {
            return super.koreanAge
        }
        set {
            age = newValue
        }
    }
}
현재 위의 Student는 Person클래스를 상속 받고 있는, 즉 Sub-Class이다. 그리고 읽기전용 계산프로퍼티인 introduce를 재정의 하고 있다. 그러나 getter블록의 return 되는 값을 보면 super키워드 명시되어 있다. 이것이 의미하는 것은 무엇일까?
 override var introduce: String { // 재정의 
        return super.introduce + ", \(grade)"
    }
만약 재정의를 하였는데 Super-Class의 프로퍼티를 수정하지 않고 사용하고 싶다면, super 키워드를 프로퍼티 앞에 명시해야 한다.
let s = Student()
s.name = "홍길동"
s.age = 99
s.grade // "F"
s.introduce
// 제 이름은 홍길동이고, 나이는 99입니다. 그리고 성적은 F입니다."
재정의한 introduce에 접근을 하면, 인스턴스의 프로퍼티에 저장한 값을 기준으로 Super-Class로 부터 상속받은 "제 이름은 홍길동이고, 나이는 99입니다." 와 Sub-Class에서 재정의한 "그리고 성적은 F입니다." 가 반환된다.
그러나 저장프로퍼티를 재정의 할 때, 저장프로퍼티로 재정의 하는 것은 불가능하다. 이름과 타입은 항상 동일하게 일치시켜주어야 하지만 종류는 읽기와 쓰기가 가능한 연산프로퍼티로 재정의를 하거나, 감시자를 추가시켜 재정의를 해야 한다.
class Imagine: Student {
    override var grade: String {
        didSet {
            if grade != "A+" {
                print("이왕 바뀌는 거라면 A+로 합시다.")
            } else {
                print("제 점수는 A+입니다")
            }
        }
    }
}
var aPlus = Imagine()
aPlus.grade = "A+"
Super-Class의 저장프로퍼티인 grade를 Sub-class에서 감시자를 추가시켜 재정의 하였다. "A+"로 저장하지 않고 다른 문자열리터럴을 저장한다면 계속해서 A+로 바꾸라는 명령문이 출력될 것이다.

* 재정의 정리

  • 저장프로퍼티 => ( 재정의 ) => 읽기/쓰기 계산프로퍼티 or 감시자 추가
  • 읽기/쓰기 계산프로퍼티 => ( 재정의 ) => 읽기/쓰기 계산프로퍼티 or 감시자 추가
  • 읽기전용 계산프로퍼티 => ( 재정의 ) => 읽기전용계산프로퍼티 or 읽기/쓰기 계산프로퍼티
  • 메소드 => (재정의) => 메소드

* 타입프로터피, 타입메소드를 재정의 할때.....

타입계산프로퍼티를 정의할때 기본적으로 static을 사용하는데, 만약 재정의도 고려해서 정의를 할것이라면 Super-class의 타입계산속성에 class 키워드를 붙여서 사용한다. 그리고 Sub- Class에서 재정의된 타입계산프로퍼티에는 override키워드와 static을 사용한다.(마지막 재정의 계산프로퍼티라면)
  • 타입계산프로퍼티를 재정의 할것 이라면 Super-Class의 타입계산속성 앞에 class 키워드를 붙여야 한다.
  • 타입메소드 또한 재정의를 전제로 정의를 하고 싶다면 Super-Class 타입메소드 앞에 class키워드를 붙여야 한다,
  • 물론 재정의한 타입(메소드/계산프로퍼티)을 다시 재정의 할 것이라면 overriding과 class키워드를 사용하면 된다.

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN