티스토리 뷰

Swift/야곰의 스위프트

18장 상속

할루루 2018. 2. 28. 12:22

[시작]


- 클래스는 메서드나 프로퍼티 등을 다른 클래스로부터 상속받을 수 있음

 : 자식 클래스 : 어떤 클래스로부터 상속을 받은 클래스

 : 부모 클래스 : 자식 클래스에게 자신의 특성을 물려준 클래스

- 자식 클래스는 부모 클래스의 메서드, 프로퍼티, 서브스크립트를 사용할 수 있음

- 자식 클래스는 부모 클래스로부터 물려받은 것들을 재정의할 수 있음

- 기반 클래스 : 다른 클래스로부터 상속을 받지 않은 클래스



[클래스 상속]



1
2
3
class 클래스이름: 부모클래스이름{
    프로퍼티와 메서드들
}
cs


코드 재사용 용이, 기능 확장 시 기존 클래스를 변경하지 않고도 새로운 기능을 추가한 클래스를 정의할 수 있음



[재정의]


- 자식 클래스는 부모 클래스로부터 물려받은 특성 (인스턴스 메서드, 타입 메서드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트 등)을 그대로 사용하지 않고 자신만의 기능으로 변경하여 사용할 수 있음

- override 키워드 사용

- 재정의했을 때 부모 클래스의 특성을 자식 클래스에서 사용하고 싶다면 super 프로퍼티를 사용함

 : super.someMethod() : 부모 클래스의 메서드 호출

 : super.someProperty : 부모 클래스의 프로퍼티 접근

 : super[index] : 부모 클래스의 서브스크립트 접근



[메서드 재정의]


- Swift에서는 메서드의 반환 타입이나 매개변수가 다르면 서로 다른 메서드로 취급하므로 같은 형태를 가진 메서드를 재정의할 때만 override 키워드를 붙여주면 됨



[프로퍼티 재정의]


- 저장 프로퍼티는 재정의할 수 없음

 : 프로퍼티 자체가 아닌 접근자, 설정자, 프로퍼티 감시자를 재정의할 수 있음

- 프로퍼티를 상속받은 자식 클래스에서는 조상 클래스의 프로퍼티 종류는 알지 못하고 단지 이름과 타입만 앎

 : 재정의하려는 프로퍼티는 조상 클래스의 프로퍼티와 이름과 타입이 일치해야 함

- 조상 클래스에서 읽기 전용 프로퍼티였던 것을 자식 클래스에서 읽고 쓰기 가능한 프로퍼티로 재정의할 수 있음

 : 읽고 쓰기가 가능한 프로퍼티를 읽기 전용으로 재정의할 수 없음

 : 기능 확장 가능, 축소 불가능?

- 읽고 쓰기가 가능한 프로퍼티를 재정의할 때 접근자와 설정자 모두 재정의해야 함

 : 접근자에 따로 기능 변경이 없다면 super 프로퍼티를 활용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Person{
    var name: String = ""
    var age: Int = 0
    var koreanAge: Int{
        return self.age + 1
    }
    var introduction: String{
        return "이름 : \(name), 나이 : \(age)"
    }
}
 
class Student: Person{
    var grade: String = "F"
    override var introduction: String{
        return super.introduction + " " + "학점 : \(self.grade)"
    }
    override var koreanAge: Int{
        get{
            return super.koreanAge
        }
        set{
            self.age = newValue - 1
        }
    }
}
cs





[프로퍼티 감시자 재정의]


- 상수 저장 프로퍼티나 읽기 전용 연산 프로퍼티에는 프로퍼티 감시자를 재정의할 수 없음

 : 애초에 값을 설정할 수 없음

- 프로퍼티의 접근자와 프로퍼티 감시자는 동시에 재정의할 수 없음

 : 접근자 부분에 프로퍼티 감시자의 역할을 구현해야 함



[서브스크립트 재정의]


- 매개변수와 반환 타입이 다르면 다른 서브스크립트로 취급하므로 자식 클래스에서 재정의하려는 서브스크립트는 부모 클래스 서브스크립트의 매개변수와 반환 타입이 같아야 함



[재정의 방지]


- final 키워드 명시

 : 부모 클래스를 상속받은 자식 클래스에서 몇몇 특성을 재정의할 수 없도록 제한하고 싶다면 재정의를 방지하고 싶은 특성 앞에 명시

 : 클래스를 상속하거나 재정의할 수 없도록 하고 싶다면 class 키워드 앞에 명시



[클래스의 이니셜라이저 - 시작]


- 값 타입(구조체 등)의 이니셜라이저(이하 생성자)는 생성자 위임을 위해 생성자끼리 구분할 필요가 없었음

- 참조 타입(클래스)에서는 지정 생성자와 편의 생성자로 역할을 구분함

- 또한 상속이 가능하므로 상속받았을 때 생성자를 어떻게 재정의하는지도 생각해야 함



[지정 생성자와 편의 생성자]


- 지정 생성자 Designated Initializer

 : 주요 생성자

 : 부모 클래스의 생성자 호출 가능

 : 생성자가 정의된 클래스의 모든 프로퍼티를 초기화해야 함

 : 모든 클래스는 하나 이상의 지정 생성자를 가짐


- 편의 생성자 Convenience Initializer

 : 지정 생성자를 자신 내부에서 호출

 : 지정 생성자의 매개변수가 많아 외부에서 일일이 전달인자를 전달하기 어렵거나 특정 목적에 사용하기 위해 설계할 수 있음

 : 필수 요소는 아니지만 유용하게 사용될 수 있음

1
2
3
4
5
6
7
8
9
//지정 이니셜라이저 정의 구문
init(매개변수들){
    초기화 구문
}
 
//편의 이니셜라이저 정의 구문
convenience init(매개변수들){
    초기화 구문
}
cs




[클래스의 초기화 위임]


- 자식 클래스의 지정 생성자는 부모 클래스의 지정 생성자를 반드시 호출해야 한다.

- 편의 생성자는 자신을 정의한 클래스의 다른 생성자를 반드시 호출해야 한다.

- 편의 생성자는 궁극적으로는 지정 생성자를 반드시 호출해야 한다.



[2단계 초기화]


- Swift의 클래스 초기화는 2단계를 거침


- 1단계 : 클래스에 정의한 각각의 저장 프로퍼티에 초기값이 할당됨

- 2단계 : 저장 프로퍼티를 사용자 정의 할 기회를 얻음

- 이후 새로운 인스턴스를 사용할 준비가 끝남


- 프로퍼티를 초기화하기 전에 프로퍼티 값에 접근하는 것을 막아 초기화를 안전하게 진행할 수 있게 함

- 다른 생성자가 프로퍼티의 값을 실수로 변경하는 것을 방지함


- 2단계 초기화를 오류 없이 처리하기 위해 실행하는 안전 확인

 : 자식 클래스의 지정 생성자가 부모 클래스의 생성자를 호출하기 전에 자신의 프로퍼티를 모두 초기화했는지 확인

 : 자식 클래스의 지정 생성자는 상속받은 프로퍼티에 값을 할당하기 전에 반드시 부모 클래스의 생성자를 호출해야 함

 : 편의 생성자는 자신의 클래스에 정의한 프로퍼티를 포함하여 그 어떤 프로퍼티라도 값을 할당하기 전에 다른 생성자를 호출해야 함

 : 초기화 1단계를 마치기 전까지는 생성자는 인스턴스 메서드를 호출할 수 없음. 인스턴스 프로퍼티의 값을 읽어들일 수 없음. self 프로퍼티를 자신의 인스턴스를 나타내는 값으로 활용할 수 없음.


- 클래스의 인스턴스는 초기화 1단계를 마치기 전까지는 유효하지 않음. 프로퍼티는 읽기 가능하고, 메서드는 호출될 수 있을 뿐임

- 클래스의 인스턴스가 초기화 1단계를 마쳐야 비로소 유효한 인스턴스가 됨



- 초기화 1단계

 1. 클래스가 지정 또는 편의 생성자를 호출

 2. 그 클래스의 새로운 인스턴스를 위한 메모리가 할당됨. 메모리는 아직 초기화되지 않음

 3. 지정 생성자는 클래스에 정의된 모든 저장 프로퍼티에 값이 있는지 확인. 현재 클래스 부분까지의 저장 프로퍼티를 위한 메모리는 이제 초기화되었음.

 4. 지정 생성자는 부모 클래스의 생성자가 같은 동작을 행할 수 있도록 초기화를 양도함.

 5. 부모 클래스는 상속 체인을 따라 최상위 클래스에 도달할 때까지 이 작업을 반복함.

- 최상위 클래스에 도달했을 때 최상위 클래스까지의 모든 저장 프로퍼티에 값이 있다고 확인하면 해당 인스턴스의 메모리는 모두 초기화된 것


- 초기화 2단계

 1. 최상위 클래스로부터 최하위 클래스까지 상속 체인을 따라 내려오면서 지정 생성자들이 인스턴스를 제각각 사용자 정의하게 됨. 이 단계에서는 self를 통해 프로퍼티 값을 수정할 수 있고, 인스턴스 메서드를 호출하는 등의 작업을 진행할 수 있음

 2. 각각의 편의 생성자를 통해 self를 통한 사용자 정의 작업을 진행할 수 있음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person{
    var name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
 
class Student: Person{
    var major: String
    init(name: String, age: Int, major: String) {
        //부모 클래스의 지정 생성자를 호출하기 전에 자신의 저장 프로퍼티를 먼저 초기화함
        self.major = major
        //부모 클래스의 생성자를 호출하였고 그 외에 상속받은 프로퍼티가 없음
        super.init(name: name, age: age)
    }
    convenience init(name: String) {
        //편의 생성자가 다른 생성자를 호출함
        self.init(name: name, age: 7, major: "")
    }
}
cs




[이니셜라이저 상속 및 재정의]


- 기본적으로 Swift에서 생성자는 부모 클래스의 생성자를 상속받지 않음

 : 부모 클래스의 생성자는 자식 클래스에 최적화되어 있지 않음

 : 안전하고 적절하다고 판단되는 경우에는 부모 클래스의 생성자가 상속되기도 함

- 보통 부모 클래스의 생성자와 같은 생성자를 자식 클래스에서 사용하고 싶다면 같은 생성자를 구현해주면 됨

 : override 키워드 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person{
    var name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
 
class Student: Person{
    var major: String
    //부모 클래스의 생성자와 형태가 같으므로 override 키워드를 붙여 재정의해주어야 함
    override init(name: String, age: Int) {
        self.major = ""
        super.init(name: name, age: age)
    }
}
cs




[이니셜라이저 자동 상속]


- 자식 클래스에서 프로퍼티 기본값을 모두 제공한다고 가정할 때, 

 : 자식 클래스에서 별도의 지정 생성자를 구현하지 않는다면 부모 클래스의 지정 생성자가 자동으로 상속됨

 : 위의 규칙에 따라 자식 클래스에서 부모 클래스의 지정 생성자를 자동으로 상속받은 경우 또는 부모 클래스의 지정 생성자를 모두 재정의하여 부모 클래스와 동일한 지정 생성자를 모두 사용할 수 있다면 부모 클래스의 편의 생성자가 모두 자동으로 상속됨



[요구 이니셜라이저]


- required 키워드를 클래스의 생성자 앞에 명시하면 이 클래스를 상속받은 자식 클래스에서 반드시 해당 생성자를 구현해주어야 함

 : 상속받을 때 반드시 재정의해야 하는 생성자

- 자식 클래스에서 해당 생성자를 재정의할 때 required 키워드를 사용함


- required override 키워드를 사용하여 부모 클래스의 생성자를 재정의함과 동시에 요구 생성자로 변경함을 알림

'Swift > 야곰의 스위프트' 카테고리의 다른 글

20장 프로토콜  (0) 2018.03.01
19장 타입캐스팅  (0) 2018.03.01
17장 서브스크립트  (0) 2018.02.28
16장 모나드  (0) 2018.02.12
15장 맵, 필터, 리듀스  (0) 2018.02.12
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함