Inheritance

yescoach·2021년 7월 28일
0

Inheritance 공식문서

Inheritance

클래스는 메서드, 프로퍼티다른 특성을 다른 클래스에서 상속할 수 있습니다. 한 클래스가 다른 클래스에서 상속되는 경우 상속을 받는 클래스는 서브 클래스, 상속을 하는 클래스는 슈퍼클래스 입니다. 상속은 Swift의 다른 타입들과 클래스를 차별화하는 핵심적인 기능입니다.

Swift의 클래스는 해당 슈퍼클래스에 속하는 메서드, 프로퍼티서브스크립트를 호출하고 액세스할 수 있으며 이러한 메서드, 프로퍼티 및 서브스크립트의 동작을 세분화하거나 수정할 수 있는 자체 재정의(overriding) 버전을 제공할 수 있습니다. Swift는 재정의 정의에 일치하는 슈퍼클래스 정의가 있는지 확인하여 재정의가 올바른지 확인하는 데 도움이 됩니다.

클래스는 프로퍼티 값이 변경될 때 알림을 받기 위해 상속된 프로퍼티에 프로퍼티 옵저버를 추가할 수도 있습니다. 프로퍼티 옵저버는 원래 stored property로 정의되었는지 또는 computed property으로 정의되었는지에 관계없이 모든 속성에 추가할 수 있습니다.

Defining a Base Class

다른 클래스에서 상속되지 않는 클래스를 기본 클래스(Base Class)라고 합니다.

스위프트 클래스는 범용 기본 클래스(Universal base class)에서 상속되지 않습니다.
슈퍼 클래스를 지정하지 않고 정의한 클래스는 자동으로 빌드할 기본 클래스가 됩니다.

아래의 예는 Vehicle이라는 기본 클래스를 정의합니다. 이 기본 클래스는 기본값이 0.0(프로퍼티 타입은 Double로 추론)인currentSpeed라는 저장 프로퍼티를 정의합니다. currentSpeed 프로퍼티 값은 description이라는 read-only 연산 String 프로퍼티에서vehicle에 대한 description을 만드는 데 사용됩니다.

Vehicle 기본 클래스는 makeNoise라는 메서드도 정의합니다. 이 메서드는 기본 Vehicle 인스턴스에는 적용되지 않지만 나중에 Vehicle의 서브 클래스에서 커스터마이즈 됩니다.

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
    }
}

Initializer 구문을 사용하여 Vehicle의 새 인스턴스를 만듭니다. 이 인스턴스는 타입이름(Vehicle)과 빈 괄호()로 작성됩니다.

let someVehicle = Vehicle()

Vehicle 인스턴스를 만든 후에는, description 프로퍼티에 액세스하여 사람이 읽을 수 있는 차량 현재 속도에 대한 description을 출력할 수 있습니다.

print("Vehicle: \(someVehicle.description)")
// Vehicle: Traveling at 0.0 miles per hour

Vehicle 클래스는 임의의 차량에 대한 일반적인 특성을 정의하지만 그 자체로는 그다지 유용하지 않습니다. 이 클래스를 더 유용하게 만들기 위해서는, 더 구체적인 종류의 차량을 표현할 수 있도록 다듬어야 합니다.

Subclassing

Subclassing은 기존 클래스를 기반으로 새 클래스를 만드는 작업입니다. 서브클래스는 기존 클래스의 특성을 상속하며, 이 특성을 세분화할 수 있습니다. 서브클래스에 새 특성을 추가할 수도 있습니다.

서브 클래스superclass가 있음을 나타내려면 superclass 이름 앞에 subclass 이름을 콜론으로 구분하여 기록합니다.

class SomeSubclass: SomeSuperclass {
	// subclass definition goes here
}

다음은 Vehicle이라는 슈퍼클래스가 있는, Bicycle이라는 서브클래스를 정의하는 예입니다.

class Bicycle: Vehicle {
	var hasBasket = false
}

새로운 Bicycle클래스는 currentSpeeddescriptionmakeNoise() 메소드 등 Vehicle의 모든 특성을 자동으로 획득합니다.
Bicycle 클래스는 상속되는 특성 외에도 새 저장 프로퍼티를 정의하며 기본값이 false(프로퍼티 타입 유추(Bool))인 hasBasket를 가집니다.

기본적으로 새로 만드는 모든 Bicycle 인스턴스에는 basket이 없습니다.
특정 Bicycle 인스턴스가 생성된 후 hasBasket 속성을 true로 설정할 수 있습니다.

let bicycle = Bicycle()
bicycle.hasBasket = true

Bicycle 인스턴스의 상속된 currentSpeed 프로퍼티를 수정하고 인스턴스의 상속된 description프로퍼티를 쿼리할 수도 있습니다.

bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour

서브클래스 자체가 서브클래스가 될 수 있습니다. 다음 예에서는 "tandem" 으로 알려진 2인승 Bicycle의 서브클래스를 만듭니다.

class Tandem: Bicycle {
	var currentNumberOfPassengers = 0
}

TandemBicycle로부터 모든 프로퍼티 및 메소드를 상속받는데, 이는 Vehicle으로부터 상속받은 모든 프로퍼티 및 메소드입니다.
또한 Tandem 서브클래스는 기본값이 0인 currentNumberOfPassengers라는 새 저장 프로퍼티를 추가합니다.

Tandem 인스턴스를 만드는 경우, Tandem의 새 프로퍼티와 상속된 프로퍼티로 작업하고 Vehicle에서 상속되는 read-only description 설명 속성을 쿼리할 수 있습니다.

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

Overriding

서브클래스는 인스턴스 메서드, 타입 메서드, 인스턴스 프로퍼티, 타입 프로퍼티 또는 슈퍼클래스로부터 상속되는 서브스크립트의 사용자 지정 구현을 제공할 수 있습니다. 이것을 재정의(오버라이드)라고 합니다.

상속될 특성을 재정의하려면 재정의 정의에 override키워드 접두사를 지정합니다. 이렇게 하면 오버라이드 할 의도이며 실수로 일치하는 정의를 제공하지 않았음을 알 수 있습니다. 실수로 재정의하면 예기치 않은 동작이 발생할 수 있으며 override 키워드가 없는 재정의는 코드를 컴파일할 때 오류로 진단됩니다.

override 키워드는 또한 Swift 컴파일러에게 오버라이딩 클래스의 슈퍼클래스(또는 상위 클래스 중 하나)에 오버라이드 선언과 일치하는 선언이 있는지 확인하라는 메시지를 표시합니다. 이 검사는 오버라이드 정의가 올바른지 확인합니다.

Accessing Superclass Methods, Properties, and Subscripts

서브클래스에 대한 메서드, 프로퍼티 또는 서브스크립트 오버라이드를 제공할 때 기존 슈퍼클래스 구현을 오버라이드의 일부로 사용하는 것이 유용한 경우가 있습니다. 예를 들어 기존 구현의 동작을 세분화하거나 수정된 값을 기존 상속 변수에 저장할 수 있습니다.

적절한 경우 super접두사를 사용하여 메서드, 프로퍼티 또는 서브스크립트의 superclass 버전에 접근합니다.

  • someMethod()라는 오버라이드 메서드는 오버라이드 메서드 구현 내에서 super.someMethod()를 호출하여 someMethod()의 슈퍼클래스 버전을 호출할 수 있습니다.
  • someProperty라는 오버라이드된 속성은 somePropertysuperclass 버전에 오버라이딩 된 getter 또는 setter 구현이 포함된super.someProperty로 액세스할 수 있습니다.
  • someIndex라는 오버라이드된 서브스크립트는 super[someIndex]과(와) 동일한, [someIndex]를 재정의하는 서브스크립트 구현 내에서 가져온 서브스크립트의 superclass 버전에 액세스할 수 있습니다.

Overriding Methods

상속된 인스턴스 또는 타입 메서드를 재정의하여 서브클래스 내에서 메서드의 맞춤형 또는 대체 구현을 제공할 수 있습니다.
다음 예제는 TrainVehicle에서 상속하는 makeNoise() 메소드를 재정의하는 Train이라는 새로운 Vehicle의 서브클래스를 정의합니다.

class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}

새로운 Train 인스턴스를 만들고 makeNoise() 메서드를 호출하면 Train 서브클래스 버전의 메서드를 다음과 같이 호출할 수 있습니다.

let train = Train()
train.makeNoise()
// Prints "Choo Choo"

Overriding Properties

상속된 인스턴스 또는 타입 프로퍼티를 재정의하여 해당 프로퍼티에 대한 사용자 지정 gettersetter를 제공하거나, 오버라이딩 프로퍼티가 기본 속성 값이 변경될 때 관찰할 수 있도록 프로퍼티 옵저버를 추가할 수 있습니다.

Overriding Property Getters and Setters

상속된 프로퍼티가 저장 프로퍼티으로 구현되는지 또는 연산 프로퍼티로 구현되는지에 대한 여부와 관계없이, 상속된 프로퍼티를 재정의하는 사용자 지정 getter(및 적절한 경우)를 제공할 수 있습니다. 상속된 저장 또는 연산 프로퍼티는 서브클래스에서 알 수 없습니다. 상속된 프로퍼티의 이름과 타입이 특정하다는 것만 알 수 있습니다. 재정의할 프로퍼티의 이름과 타입을 항상 명시해야 컴파일러에서 재정의할 이름과 타입이 동일한 슈퍼클래스 속성과 일치하는지 확인할 수 있습니다.

서브클래스 프로퍼티 재정의에서 gettersetter를 모두 제공하여 상속된 read-only propertyread-write property으로 나타낼 수 있습니다. 그러나 상속된 read-write propertyread-only property로 제공할 수 없습니다.

NOTE
프로퍼티 재정의의 일부로 setter를 제공하는 경우 해당 재정의에 대한 getter도 제공해야 합니다. 재정의한 getter로 상속된 프로퍼티 값을 수정하지 않으려면 getter에 super.someProperty를 반환하여 상속된 값을 통과하면 됩니다. 여기서 someProperty는 재정의할 속성의 이름입니다.

다음 예에서는 Car이라는 새로운 클래스를 정의합니다. 이 클래스는 Vehicle의 슈퍼클래스입니다. Car 클래스는 기본 정수 값이 1인 gear라는 새 저장 프로퍼티를 구현합니다. 또한 car 클래스는 Vehicle으로부터 상속되는 description 프로퍼티를 오버라이드하여 현재 gear가 포함된 사용자 지정 description을 제공합니다.

class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}

description 프로퍼티의 재정의는 super.description을 호출하는 것으로 시작되며, 이 경우 Vehicle 클래스의 description 프로퍼티가 반환됩니다. 그런 다음 Car 클래스의 description 버전은 이 description 끝에 현재 gear에 대한 정보를 제공하기 위해 텍스트를 추가합니다.

Car 클래스의 인스턴스를 만들고 해당 gearcurrentSpeed 프로퍼티을 설정하면 해당 description property가 Car 클래스에 정의된 맞춤형 설명을 반환하는 것을 볼 수 있습니다.

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

Overriding Property Observers

프로퍼티 오버라이딩을 사용하여 상속된 프로퍼티에 프로퍼티 옵저버를 추가할 수 있습니다. 이렇게 하면 해당 프로퍼티가 처음 구현된 방식에 관계없이 상속된 프로퍼티의 값이 변경될 때 알림을 받을 수 있습니다. 프로퍼티 옵저버에 대한 자세한 내용은 Property Observers를 참조하십시오.

NOTE
상속된 상수 저장 프로퍼티 또는 상속된 read-only 연산 프로퍼티에 프로퍼티 옵저버를 추가할 수 없습니다. 이러한 프로퍼티 값은 설정할 수 없으므로 오버라이드의 일부로 willSet 또는 didSet 구현을 제공하는 것은 적절하지 않습니다.
또한 동일한 프로퍼티에 대해 오버라이딩 setter오버라이딩 프로퍼티 옵저버를 모두 제공할 수 없습니다. 프로퍼티의 값 변경을 관찰하려는 경우, 해당 프로퍼티에 대한 사용자 지정 setter를 이미 제공 중인 경우 사용자 지정 setter 내에서 모든 값 변경을 관찰할 수 있습니다.

다음 예제에서는 AutomaticCar라는 새로운 클래스를 정의합니다. 이 클래스는 Car의 서브클래스입니다. AutomaticCar 클래스는 자동 변속 장치가 장착된 Car을 나타내며, 자동 변속 장치는 현재 속도에 따라 적합한 기어를 자동으로 선택합니다.

class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}

AutomaticCar 인스턴스의 currentSpeed 프로퍼티를 설정할 때마다 프로퍼티의 didSet 옵저버가 인스턴스의 gear 프로퍼티를 새 속도에 적합한 기어 선택으로 설정합니다. 특히, 프로퍼티 옵저버는 새로운 currentSpeed 값을 10으로 나누고 가장 가까운 정수로 반올림하여 1을 더한 기어를 선택합니다. 35.0의 속도는 4의 기어를 생성합니다.

let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4

Preventing Overrides

메서드, 프로퍼티 또는 서브스크립트final로 표시하여 오버라이드하지 못하도록 할 수 있습니다. 메서드, 프로퍼티 또는 서브스크립트의 introducer 키워드 앞에 final modifier 를 작성하여 이 작업을 수행합니다.(예: final var, final func, final class func 및 final subscript)

서브클래스의 final 메서드, 프로퍼티 또는 서브스크립트를 오버라이드 하려고 하면 컴파일 타임 에러로 보고됩니다. 확장(extension)에서 클래스에 추가하는 메서드, 프로퍼티 또는 서브스크립트도 확장 정의 내에서 final으로 표시할 수 있습니다.

클래스 정의에서 class 키워드 앞에 final을 작성하여 전체 클래스를 final으로 표시할 수 있습니다(final class). final 클래스를 서브클래스 하려는 시도는 컴파일 타임 에러로 보고됩니다.

profile
iOS dev / Japanese with Computer Science

0개의 댓글