<aside> 💡 재정의(overriding) - 현재의 클래스에 맞게 상위 멤버를 변형시키서, 사용 하려는 것
대원칙:
(재정의를 하지 않아도, 상속에서는 당연히 모든 멤버의 상속이 일어남)
저장 속성은 실제 인스턴스에 각각의 멤버별(속성별로) 저장공간이 있고,
변형하는 것이 불가 (상속의 기본 원칙)
메서드는 타입(데이터 영역)에만 배열형태로 주소값을 저장되어 존재하므로
각 상속단계에서 재정의 되고 대체 되는 것이 당연
</aside>
<aside>
💡 서브클래스에서는 부모클래스에서 상속받은 것을 재정의 할 수 있습니다.
이것을 overriding
이라 부르는데, 오버라이딩은 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트 모두에 대해 가능합니다.
오버라이드를 위해서는 다른 선언 앞에 override
키워드를 붙여줍니다.
Swift에서는 이 override
키워드를 보면 부모에 그 정의가 있는지 확인합니다.
</aside>
<aside>
💡 서브클래스에서는 상속받은 저장된 프로퍼티, 계산된 프로퍼티 모두 오버라이드 가능합니다. 오버라이드시에는 프로퍼티의 이름과 타입을 명시해야합니다. 왜냐하면 서브클래스에서는 단순히 상속받은 특정 형의 프로퍼티가 있다는 정도만 알고 있기 때문입니다. 상속받은 읽기전용(read only) 프로퍼티도 getter/setter
를 정의해서 읽고/쓰기가 가능한(read-write) 프로퍼티로 변경해서 제공 가능합니다. 하지만 반대의 읽고/쓰기가 가능한 프로퍼티를 읽기전용 프로퍼티로 선언하는 것은 할 수 없습니다.
만약 setter
를 오버라이드 해서 제공한다면 반드시 getter
도 제공해야 합니다.
</aside>
class 탈것 {
var 경적소리 = "빵"
}
class 자동차: 탈것 {
var 경적횟수: Int = 2
override var 경적소리: String {
get {
var 자동차경적소리 = ""
for _ in 0..<경적횟수 {
자동차경적소리 += super.경적소리
}
return 자동차경적소리
}
set {
super.경적소리 = newValue
}
}
}
let vehicle = 탈것()
let car = 자동차()
print(car.경적소리) // 빵빵
// 참조타입이므로 외부에서 super 클래스의 프로퍼티를 달라고해도 car 내부에서 구현된 상태로 나온다.
print((car as 탈것).경적소리) // 빵빵
print(vehicle.경적소리) // 빵
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
let train = Train()
train.makeNoise()
// Prints "Choo Choo" : 새로 정의한 내용이 출력됩니다.
상수 프로퍼티와 읽기전용 프로퍼티에는 옵저버를 붙일 수 없습니다. 이 프로퍼티는 정의 그대로 set
을 할 수 없는 프로퍼티이기 때문입니다. 또 같은 프로퍼티에 옵저버를 추가하고 setter
를 추가해 둘을 동시에 사용할 수 없습니다. 이미 setter
를 설정했다면 옵저버를 붙인 것과 같은 동작을 하기 때문입니다.
class 특이한자동차: 자동차 {
override var 경적횟수: Int {
didSet {
경적소리 = "뿡"
}
}
}
let specialCar = 특이한자동차()
// 경적횟수를 지정해주면, 알아서 경적소리를 뿡으로 바꿈
specialCar.경적횟수 = 3
print(specialCar.경적소리) // 뿡뿡뿡