
상속은 이미 만들어 놓은 클래스의 메소드, 프로퍼티 등을 바로 사용할 수 있는 방법으로, 흔히 부모 클래스(superclass)를 자식 클래스(subclass)가 상속한다고 이야기한다. 클래스만의 특징인 상속을 통해 코드를 효율적으로 사용할 수 있다.
커스텀 또한 가능하다. 서브클래스가 새로 쓰고 싶은 메소드 또는 프로퍼티를 오버라이딩할 수 있다.
기존의 클래스와 마찬가지로 상속받은 서브클래스 프로퍼티 값 또한 프로퍼티 옵저버를 통해 값 변화를 확인할 수 있다.
다른 클래스에서 상속하지 않은 클래스, 즉 자식 클래스가 아닌 클래스를 베이스 클래스라 정의하자. 스위프트에서 수퍼클래스를 명시하지 않고 클래스를 정의하면 자동으로 베이스 클래스가 된다.
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
Vehicle 클래스는 현재 속도와 이를 사용한 프린트문을 출력한다. 이를 활용해 기능을 추가해보자.
정의된 클래를 상속해 새로운 클래스를 만들고 기능을 수정 및 추가하자. : 콜론으로 서브클래스 뒤에 상속할 수퍼클래스 이름을 붙인다.
class Bicycle: Vehicle {
var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour
수퍼클래스 Vehicle을 상속하는 Bicycle, Tandem은 각각 수퍼클래스 기능을 사용하면서 자신만의 유니크한 기능을 추가할 수 있다.
수퍼클래스가 제공하는 메소드, 프로퍼티 등을 서브클래스에서 활용하도록 커스텀할 수 있다. 즉, 오버라이딩할 수 있다. override 키워드로 상속받은 기능을 그대로 쓰는 게 아니고 새로 정의한 기능임을 스위프트에 알려주자. 컴파일러는 서브클래스에서 오버라이딩한 부분이 수퍼클래스의 타입과 매칭되는지 자동으로 확인해준다.
super라는 접두사를 써서 오버라이딩한 메소드 안에서도 수퍼클래스의 내용을 적용할 수 있다. 즉, 일부는 그대로, 일부는 커스텀한 기능을 추가하는데 super를 통해 코드 사용을 줄일 수 있다.
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
let train = Train()
train.makeNoise()
// Prints "Choo Choo"
Train 서브클래스는 Vehicle을 상속하면서도 makeNoise()를 유니크하게 사용한다.
오버라이딩할 프로퍼티 이름과 타입을 명시해서 컴파일러가 같은 이름과 타입을 가진 수퍼클래스의 프로퍼티와 매치되도록 해야 한다.
세터를 오버라이딩하려면 게터도 오버라이딩해야 한다. 앞서 말한대로 super를 통해 기존 값을 그대로 사용할 수도 있다.
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3
Car의 수퍼클래스 Vehicle의 description을 super로 끌어와 덧붙이고 있다.
상속받은 프로퍼티에 대한 프로퍼티 옵저버를 추가할 수 있다. 물론 상속한 저장 프로퍼티 타입이 상수거나 읽기 전용 연산 프로퍼티라면 프로퍼티 옵저버를 사용할 수 없다. didSet이나 willSet을 지원해야 하기 때문.
동일한 프로퍼티를 두고 세터와 옵저버를 모두 사용할 수 없다. 값이 바뀐 것을 관찰하려면 커스텀 세터 안에서 프로퍼티 값이 어떻게 바뀌는지 관찰하자.
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
didSet 옵저버가 gear 프로퍼티 값이 어떻게 바뀌는지 가지고 있다.
메소드, 프로퍼티, 서브스크립트가 오버라이드되지 않도록 final 키워드를 사용해 고정시키자. 클래스 자체도 final class로 정의하면 이 클래스에 대한 서브클래스는 생성할 수 없다.