- 상속이란? 기존(부모) 클래스에 구현된 변수(프로퍼티)/메소드를 상속받은 새로운(자식) 클래스가 그대로 사용가능한 상태를 의미한다.
- Swift 클래스 상속
- 클래스의 상속은 단일 상속만 허용한다. 즉 자식 클래스는 하나의 부모 클래스만 상속한다.
- 문법클래스 상속 문법
class Child Class Name : Parent Class Name {
} - 클래스 상속과 포인터
- self, super
- self 포인터는 현재 자신의 클래스 내에 있는 프로퍼티/메소드에 접근 시에 사용한다.
- super 포인터는 자신이 상속하고 있는 부모 클래스의 프로퍼티/메소드 접근 시에 사용한다.
- self 포인터와 super 포인터 사용 예시는 아래와 같다.self 포인터와 super 포인터
// 부모 클래스
class Parent {
func description() -> String { return "Parent Class" }
}
// 자식 클래스
class Child {
// 메소드 재정의
override func description() -> String {
return "Child Class"
}
func printDescription() {
print("super.description : \(super.description())")
// "Parent Class" 출력
print("self.description : \(self.description())")
// "Child Class" 출력
}
} - 클래스 상속과 재정의
- 클래스 상속은 부모 클래스의 프로퍼티/메소드를 자식 클래스에서 그대로 사용 가능하다.
- 메소드 재정의
- 부모 클래스에 있는 상속받은 메소드(같은 이름의 메소드)를 자식 클래스에서 다른 동작을 하도록 다시 정의하는 것을 메소드 재정의 라고 한다.
- 메소드 재정의는 메소드 앞에 override 키워드를 이용하여 재정의한다.메소드 재정의
// 부모 클래스
class Parent {
var value = 0
func hello() {
print("Hello Parent Class")
}
}
// 자식 클래스
class Child : Parent { // Parent 클래스 상속
override func hello() { // 동일 이름의 다른 동작
print("Hello Child Class")
}
}
- 프로퍼티 재정의
- 부모 클래스에 정의된 프로퍼티를 재정의 한다.
- 프로퍼티 재정의 시에도 메소드 재정의와 동일하게 앞에 override 키워드를 이용한다.
- 저장 프로퍼티 재정의
- 방법 : willSet/didSet 행위를 추가해준다.저장 프로퍼티 재정의
// 사각형의 부모 클래스
class Rectangle {
var width = 0
var height = 0
var size : Int {
get{return width * height}
}
}
// 정사각형의 자식 클래스
class Square : Rectangle { // Rectangle 클래스를 상속
override var width : Int {
didSet(newValue) {
// 새로 추가되는 행위
self.width += newValue
}
}
} - 계산 프로퍼티 재정의
- 방법 : get/set 행위를 재정의해준다.계산 프로퍼티 재정의
// 사각형의 부모 클래스
class Rectangle {
var width = 0
var height = 0
var size : Int {
get{return width * height}
}
}
// 정사각형의 자식 클래스
class Square : Rectangle { // Rectangle 클래스를 상속
override var size : Int {
get {
height = width
return width * height
}
}
} - 재정의 시 주의사항
- 재정의가 필요한 프로퍼티/메소드에 override 키워드 누락 시에 에러 발생
- 재정의하는 대상이 아닌 프로퍼티/메소드에 override 키워드 붙이는 경우 에러 발생
- 부모 클래스의 프로퍼티/메소드 앞에 final 키워드가 붙은 경우는 재정의가 금지된 것으로 자식 클래스에서 재정의 할 수 없다.
- 클래스 상속과 초기화
- 자식 클래스는 부모 클래스의 프로퍼티를 상속하게 된다.
- 부모 클래스에 초기화가 필요한 프로퍼티가 있는 경우, 자식 클래스에서의 초기화는 아래와 같다.
- 자식 클래스에 Designated Initializer 가 없는 경우 부모 클래스의 Designated, Convenience Initializer 모두 상속한다.부모 클래스의 Initializer 상속
// 부모 클래스
class Parent {
var a : Int
init(a : Int) {
self.a = a
}
convenience init() {
self.init(a : 10)
}
}
// 자식 클래스
class Child : Parent {
// 부모 클래스에 있는 Initializer 를 모두 상속
}
// 객체 생성
var ChildObj1 = Child(a : 20) // Designated Initializer 상속
var ChildObj2 = Child() // Convenience Initializer 상속 - 자식 클래스에 Designated Initializer 가 있는 경우 부모 클래스의 Designated, Convenience Initializer 모두 상속하지 못한다.부모 클래스의 Initializer 상속 못함
// 부모 클래스
class Parent {
var a : Int
init(a : Int) {
self.a = a
}
convenience init() {
self.init(a : 10)
}
}
// 자식 클래스
class Child : Parent {
var b : Int
init(a : Int, b : Int) {
self.b = b
super.init(a : a)
}
/* 자식 클래스에 Designated Initializer 가 있는 경우 부모 클래스의 Initializer 를 상속받지 못함 */
}
// 객체 생성
// 자식 클래스의 Designated Initializer
var ChildObj1 = Child(a : 20, b : 30)
// 부모 클래스의 Initializer 를 상속 받지 못함
var ChildObj2 = Child(a : 20)
var ChildObj3 = Child() - 자식 클래스에서 Designated Initializer 를 정의하지 않고, Convenience Initializer를 부모 클래스의 Designated Initializer를 상속부모 클래스의 Designated Initializer 상속
// 부모 클래스
class Parent {
var a : Int
init(a : Int) {
self.a = a
}
convenience init() {
self.init(a : 10)
}
}
// 자식 클래스
class Child : Parent {
var b : Int
convenience init(a : Int, b : Int) {
self.b = b
super.init(a : a)
}
/* 자식 클래스에 Designated Initializer 가 없고 Convenience Initializer 만 정의한 경우 부모 클래스의 Initializer를 모두 상속 */
}
// 객체 생성
// 자식 클래스의 Designated Initializer
var ChildObj1 = Child(a : 20, b : 30)
// 부모 클래스의 Initializer 를 상속 받음
var ChildObj2 = Child(a : 20)
var ChildObj3 = Child() - 자식 클래스에 부모 클래스에 있는 모든 Designated Initializer를 재정의한 경우, Convenience Initializer 를 상속한다.부모 클래스의 Designated Initializer 모두 상속
// 부모 클래스
class Parent {
var a : Int
init(a : Int) {
self.a = a
}
convenience init() {
self.init(a : 10)
}
}
// 자식 클래스
class Child : Parent {
override init(a : Int) {
self.b = 20
super.init(a : a)
}
/* 부모 클래스에 Designated Initializer 를 모두 재정의한 경우 부모 클래스의 Convenience Initializer 를 상속 */
}
// 객체 생성
var ChildObj = Child()
// 부모 클래스의 Convenience Initializer 상속 - 클래스 초기화 관계는 아래와 같다.
- 상속과 Failable Initializer
- 부모 클래스의 Failable Initializer를 자식 클래스가 위임한다.
- 자식 클래스에서 부모 클래스의 Failable Initializer 재정의하는 방법은 아래와 같다.
- Failable Initializer를 Failable Initializer로 재정의하는 방법Failable Initializer를 Failable Initializer로 재정의
// 부모 클래스
class Parent {
var value : Int
// Failable Initializer
init?(value : Int) {
if(value < 0) {
return nil
}
self.value = value
}
// Non-Failable Initializer
init() {
self.value = 0
}
}
// 자식 클래스
class Child : Parent {
override init?(value : Int) {
// Failable Initializer로 위임
super.init(value : value)
}
} - Failable Initializer를 Non-Failable Initializer로 재정의하는 방법Failable Initializer를 Non-Failable Initializer로 재정의
// 부모 클래스
class Parent {
var value : Int
// Failable Initializer
init?(value : Int) {
if(value < 0) {
return nil
}
self.value = value
}
// Non-Failable Initializer
init() {
self.value = 0
}
}
// 자식 클래스
class Child : Parent {
override init(value : Int) {
// Non-Failable Initializer로 위임
super.init()
}
} - Non-Failable Initializer를 Failable Initializer로 재정의는 할 수 없다.