Swift study - Inheritance

rbw·2022년 3월 20일
0

swift-study

목록 보기
16/17
post-thumbnail

Swift - Inheritance

클래스는 다른 클래스에서 메서드, 프로퍼티 그리고 다른 특성을 상속 할 수 있다. 다른 클래스로부터 상속될 때 상속하는 클래스는 subclass로 알려져 있으며, 상속 되는 클래스는 superclass라 불린다. 상속은 스위프트의 다른 타입과 클래스의 차별을 두는 근본적인 동작이다.

스위프트의 클래스는 슈퍼클래스에 속한 메소드, 프로퍼티 그리고 서브스크립트를 호출하고 접근이 가능하며, 메소드, 프로퍼티 그리고 서브스크립트의 재정의한 버전을 제공하여 동작을 수정할 수 있다. 스위프트는 오버라이드 정의에 매칭하는 슈퍼클래스 정의를 체크하고 그것을 체크함으로써 재정의가 정확한지에 대한 보장을 도와준다.

클래스는 또한 프로퍼티의 값의 변경을 알리기 위한 상속된 프로퍼티에 프로퍼티 옵저버를 추가 할 수 있다. 프로퍼티 옵저버는 어떠한 프로퍼티를 추가 가능하다. 원래 저장된 또는 계산된 프로퍼티로 정의된것과 관련없이.

Defining a Base Class (기본 클래스 정의)

다른 클래스에서 상속하지 않은 클래스를 베이스 클래스(base class)로 알려져 있다.

NOTE

스위프트의 클래스는 범용 클래스로부터 상속하지 않는다. 특정 슈퍼클래스의 정의 없이 정의된 클래스는 자동적으로 빌드 할 베이스 클래스가 된다.

// bass class
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
        // 아무것도 하지 않음 - 임의의 차량이 반드시 소음을 내는 것은 아니다
    }
}
// 초기화 문법을 사용하여 Vehicle의 새 인스턴스를 생성
let someVehicle = Vehicle()

// description에 접근하여 사람이 읽을 수 있는 설명을 출력
print("Vehicle: \(someVehicle.description)")
// Vehicle : 0.0 ~~

Vehicle 클래스는 임의 차량의 공통 특징을 정의하지만, 그 자체로 자주 사용하지는 않는다. 좀 더 유용하게 만들기 위해, 차량의 특정 종류에 대한 설명의 더 많은 재정의가 필요하다.

Subclassing (하위 클래스)

하위 클래스는 기존 클래스 내부에서 기반한 새 클래스의 동작이다. 하위 클래스는 기존 클래스로 부터 특성을 상속받고, 이를 재정의 가능하다. 하위 클래스에 새로운 특징을 추가 가능하다.

상위 클래스를 가진 하위클래스를 나타내기 위해 서브클래스 이름 다음에 슈퍼클래스의 이름을 적는다. 아래 예시.

class SomeSubclass: SomeSuperclass {
    // subclass definition goes here
    // 서브클래스 정의부분 
}

class Bicycle: Vehicle {
    var hasBasket = false
}

Bicycle의 클래스는 자동으로 상위 클래스의 특징을 얻는다. 프로퍼티, 메소드와 같은

이러한 상속에 특징에 외에도, 새로운 프로퍼티인 hasBasket을 기본값 false와 함께 정의하였다. (타입은 불린으로 유추된다)

// 바구니가 존재한다고 변경이 가능하다.
let bicycle = Bicycle()
bicycle.hasBasket = true

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

하위클래스는 그 자체로 하위클래스화 될 수 있다. (하위 클래스도 스스로 상속을 할 수 있다) 다음의 2인용 자전거 예시.

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

2인용 자전거의 인스턴스를 만든다면, 상속된 프로퍼티와 어떠한 새로운 프로퍼티와 함께 작업이 가능하고, 읽기 전용 프로퍼티도 조회가 가능하다.

Overriding (재정의)

서브클래스는 슈퍼 클래스로부터 상속할 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입프로퍼티 또는 서브스크립트의 고유한 사용자 정의 구현을 제공할 수 있다. 이를 재정의라고 알려져 있다.

상속될 특성을 오버라이드하려면, override 키워드를 앞에 작성해야한다. 이렇게 하면 오버라이드를 제공할 의도가 있고 실수로 매칭되는 정의를 제공하지 않았음을 명확히 할 수 있다. 실수로 오버라이드하면 예상하지 않은 동작이 발생할수 있고, 오버라이드 키워드 없는 오버라이드는 코드가 컴파일 될 때 에러를 나타낸다.

오버라이드 키워드는 또한 오버라이딩 하는 클래스의 슈퍼클래스 또는 슈퍼클래스 중 하나의 오버라이드를 위해 제공한 것과 일치하는 선언이 있는지 확인하기 위해 스위프트 컴파일러에 표시한다. 이 체크는 오버라이딩 정의가 옳은지를 보장한다.

Accessing Superclass Methods, Properties, and Subscripts (상위 클래스의 메소드, 프로퍼티, 서브스크립트에 접근)

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

적절한 경우, super 접두사를 사용함으로써, 슈퍼클래스 버전의 메소드, 프로퍼티 또는 서브스크립트에 접근한다.

  • 오버라이드된 메소드의 이름은 someMethod()이며, 이는 오버라이딩 메소드 구현부 내에서 super.someMethod()로 슈퍼클래스의 버전인 메소드를 호출 가능하다.
  • 오버라이드된 프로퍼티 someProperty는 오버라이딩된 게터 또는 세터의 구현부 내에서 super.someProperty로 슈퍼클래스 버전의 프로퍼티를 접근 가능하다.
  • 오버라이딩된 서브스크립트 someIndex는 오버라이딩 서브스크립트 구현부로 부터 super[someIndex]로 슈퍼클래스 버전의 서브스크립트에 접근이 가능하다.

Overriding Methods (메소드 재정의)

하위클래스 내에 메소드의 구현부에 대체 또는 적합한 구현을 제공하려면, 상속된 인스턴스 또는 타입 메소드를 재정의하여 가능하다.

아래의 makeNoise()를 오버라이드 한 예시.

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

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

Overriding Properties (프로퍼티 재정의)

해당 프로퍼티에 대한 사용자 지정 게터와 세터를 제공하거나, 프로퍼티 값의 변경이 일어날때마다 오버라이드된 프로퍼티가 관찰할 수 있도록 프로퍼티 옵저버를 추가하기 위해 상속된 인스턴스 또는 타입 프로퍼티를 오버라이드 가능하다.

Overriding Property Getters and Setters (프로퍼티 게터와 세터의 재정의)

사용자화 게터(그리고 세터)를 제공하여 어떤 상속된 프로퍼티를 오버라이드 할수있다. 상속된 프로퍼티가 저장된 또는 계산된 프로퍼티로 구현된것과는 관련없이. 상속된 프로퍼티의 저장되거나 또는 계산된 프로퍼티는 서브클래스에 의해 알려지지 않고, 상속된 프로퍼티에 특정 이름과 타입이 있다는 것만 알 수 있다. 항상 오버라이딩한 프로퍼티의 이름과 타입을 명시해야한다, 상위클래스의 프로퍼티와 이름과 타입이 같은지를 컴파일러가 체크할 수 있게

상속된 읽기 전용 프로퍼티를 읽기-쓰기 프로퍼티로 나타낼 수 있다. 서브클래스 프로퍼티를 오버라이드한 게터와 세터를 제공함으로써. 그러나 상속된 읽기-쓰기 프로퍼티를 읽기-전용 프로퍼티로서 나타낼 수는 없다.

NOTE

프로퍼티 오버라이드의 한 부분으로 세터를 제공한다면, 반드시 오버라이드한 게터도 제공해야한다. 오버라이딩된 게터 내부의 상속된 프로퍼티 값의 변경을 원하지 않는다면, 게터의 super.someProperty를 리턴함으로써 상속된 값을 간단히 전달이 가능하다.

gear라는 새로운 저장된 프로퍼티를 추가하였고, description을 재정의 하였다.

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

description의 재정의 프로퍼티는 super.description으로 호출되고, 이는 Vehicle 클래스의 프로퍼티를 리턴한다. 그 뒤에 새로 정의된 정보를 출력한다.

Overriding Property Observers (프로퍼티 옵저버의 오버라이딩)

상속된 프로퍼티에 프로퍼티 옵저버를 추가하기 위해 프로퍼티 오버라이딩을 사용할 수 있다. 이는 프로퍼티의 원본의 구현과 관련없이 상속된 프로퍼티 값의 변경이 일어날때마다 알려준다.

NOTE

프로퍼티 옵저버를 상속된 상수의 저장된 프로퍼티 또는 상속된 읽기-전용 계산된 프로퍼티에는 추가할 수 없다. 이러한 프로퍼티 값의 설정은 불가하고, 그래서 오버라이드의 한 부분으로 willSet, didSet를 제공하는 것은 적절하지 않다.

또한 같은 프로퍼티에 대해 오버라이딩 세터와 오버라이딩 프로퍼티 옵저버 모두는 제공이 불가하다. 프로퍼티의 값의 변경의 체크를 원하고, 이미 프로퍼티의 사용자화 세터를 제공했다면, 커스텀 세터 내에서 값의 변경을 관찰하면 된다.

// 자동 기어를 나타내는 예시
class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}

위 클래스 인스턴스 프로퍼티인 currentSpeed를 설정할 때마다, didSet 옵저버가 gear 프로퍼티를 적절한 값으로 설정한다.

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 키워드를 사용해서 메서드, 프로퍼티 또는 서브스크립트의 오버라이딩을 막을 수 있다.

오버라이드 하는 모든 시도는 컴파일 에러를 나타낸다. 클래스의 확장에서 추가한 메소드, 프로퍼티 또는 서브스크립트는 확장 정의내에서 final로 표시될 수도 있다.

final class로 작성하여 클래스에도 적용이 가능하다. 최종 클래스를 하위 클래스로 만드는 모든 시도는 컴파일 에러를 발생한다.

profile
hi there 👋

0개의 댓글