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
s.introduce
재정의한 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키워드를 사용하면 된다.