스터디를 진행하며 처음부터 다시 Swift를 공부하고 있습니다.
오늘 작성할 파트는 상속 입니다.
클래스는 다른 클래스에서 메서드, 프로퍼티, 그리고 다른 특성을 상속 (inherit)
할 수 있다.
클래스가 다른 클래스로 부터 상속될 때 상속하는 클래스를 하위 클래스 (subclass)
라고 하고
상속된 클래스를 상위 클래스 (superclass)
라고 한다.
간단히 말하면 클래스를 상속받는 클래스는 자식 클래스
고, 그 상속된 클래스는 부모 클래스
이다.
자식클래스 = 서브클래스
부모클래스 = 슈퍼클래스
공식에 이렇게 나와있으니 당연한거지만 구조체는 상속이 불가능하다.
상속도 단일 상속만 가능.. ( 후에 배울 프로토콜처럼 : 뒤에 여러개를 놓을 수 없다. )
앞서 클래스와 구조체에서 설명한 적이 있으니 간단하게 형태만..
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() //-> 초기화 구문 으로 Vehicle 의 새로운 인스턴스를 생성
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
하위 클래스(Subclassing)는 기존 클래스를 기반으로 새로운 클래스를 만드는 작업이다.
하위 클래스는 기존 클래스의 특성을 상속하므로 수정할 수 있으며, 새로운 특성도 추가할 수 있다.
먼저 위의 Vehicle
클래스를 상속한 Bicycle
클래스를 선언한다.
여기서 Vehicle
은 슈퍼클래스, Bicycle
은 서브클래스라고 부른다.
class Bicycle: Vehicle {
var hasBasket = false
}
새로운 Bicycle
클래스는 위에 있는 Vehicle
의 모든 특성을 자동적으로 얻는다.
추가로 이 자전거는 현재 바구니를 가지고 있지 않다. ( 새로운 저장 프로퍼티 hasBasket
)
인스턴스가 생성된 후에 특정 Bicycle
인스턴스의 hasBasket
프로퍼티를 true
로 설정할 수 있다.
또한 상속된 프로퍼티를 수정할 수 있고 조회할 수도 있다. ( currentSpeed와 description 프로퍼티 )
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour
+) 하위 클래스는 그 자체로 하위 클래스화 될 수 있다. 그 클래스는 기존 클래스와 하위 클래스 프로퍼티를 모두 상속하게 되며, 또한 그 클래스에 새로운 프로퍼티를 추가할 수도 있다. 상속된 프로퍼티, 새로운 프로퍼티 모두 수정이 가능하고 조회도 가능하다.
부모 클래스에서 상속받은 것을 자식 클래스에서 재정의할 수 있는 것을 말한다.
오버라이딩은 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트 모두에 대해
가능하며, 상속될 특성을 재정의 하려면 앞에 override
키워드를 붙여준다.
위의 정의를 간단하게 말하자면,
내가 기존에 클래스A
를 선언했는데 클래스B
에 클래스A
를 상속한 상황이고, 이후에 클래스A
에 선언한 프로퍼티의 값들을 클래스B
에서 변경하고 싶을 때 상속 재정의를 사용한다.
예제를 통해 상속 재정의에 대해 더 자세히 보자면
class Human {
func comment() {
print("my name is dtzero")
}
}
이렇게 comment라는 메서드를 선언했는데
class Me : Human {
func comment() {
print("my name is dotzer0")
}
}
이렇게 Human을 상속한 Me 클래스에서 값을 변경하려 한다면.. 이렇게 에러가 나게 된다.
Overriding declaration requires an 'override' keyword
해당 에러를 고치기 위해 override를 사용하면 내 슈퍼클래스인 Human의 comment 함수를
내 입맛에 맞춰서 재정의해서 쓰겠다는 의미가 된다.
그럼 출력할 때 변경된 값이 출력된다.
만약 변경 전과 변경 이후의 메세지 모두 출력하고 싶다면,
super
접두어를 사용하여 메서드, 프로퍼티, 또는 서브 스크립트의 상위 클래스 버전을 접근한다.
class Me : Human {
override func comment() {
super.comment()
print("my name is dotzer0")
}
}
그리고 해당 값을 출력하면.. 변경 전과 후의 값이 모두 출력된다.
let prints: Me = .init()
prints.comment()
/*
my name is dtzero
my name is dotzer0
*/
프로퍼티에 고유한 사용자 정의 getter
와 setter
를 제공하거나 기본 프로퍼티 값이 변경될 때 재정의한 프로퍼티가 관찰할 수 있도록 프로퍼티 관찰자를 추가 하기위해 상속된 인스턴스 또는 타입 프로퍼티를 재정의할 수 있다.
주의할 점은 프로퍼티 오버라이딩을 할 때 프로퍼티의 이름과 타입을 반드시 명시해야 한다는 것이다.
먼저 앞서 배웠던 프로퍼티에는 저장 / 연산 프로퍼티가 있었다.
저장 프로퍼티의 경우, 재정의를 할 때 getter
와 setter
를 모두 구현해줘야 한다.
getter
하나만 구현하는 것도 불가능하고 구현하지 않고 재정의도 불가능하다.
class Human {
var name : String = "dtzer0"
}
class Me : Human {
var me : String = "dotzero"
override var name: String {
get {
return self.me
}
set {
self.me = name
}
}
}
출력해보면 변경된 값이 알맞게 들어가있는걸 확인할 수 있다.
var test1 : Human = .init()
print(test1.name)
var test2 : Me = .init()
print(test2.me)
/*
dtzer0
dotzero
*/
연산 프로퍼티의 경우, 부모 클래스의 연산 프로퍼티가 getter
로만 구현된 경우 서브 클래스에서 getter
만 구현하거나 setter
를 추가로 구현하는 오버라이딩은 가능하지만,
만약 부모 클래스에서 둘 다 구현했다면 서브 클래스에서 둘 다 구현해줘야한다.
해당 사항말고 나머지는 저장 프로퍼티랑 같다.
final
을 통해 실수로 메서드, 프로퍼티, 또는 서브 스크립트를 재정의 하는 것을 방지할 수 있다.
final을 class 앞에 붙이게 되면 해당 클래스는 아무도 상속할 수 없게 된다.
상속을 시도할 경우, final 클래스를 선언한걸 상속했다고 에러가 난다.
final class Human {
var name: String?
var age: Int?
}
class Me : Human {
//Inheritance from a final class 'Human'
}