[Swift] Inheritance (상속)

LEEHAKJIN-VV·2022년 5월 13일
0

Study-Swift 5.6

목록 보기
14/22

참고사이트:
The Swift Programming Language


Inheritance (상속)

클래스는 다른 클래스의 메소드, 프로퍼티, 그리고 다른 특성들을 inherit(상속)할 수 있다. 한 클래스가 다른 클래스를 상속할 때, 상속하는 클래스를 subclass(하위 클래스), 상속을 받는 클래스를 superclass(상위 클래스)라고 한다. 이는 Swift의 클래스와 다른 타입들의 클래스가 구분되는 기본적인 요소이다.

Swift에서 클래스는 상위 클래스의 메소드, 프로퍼티 및 subscript를 호출하고 그리고 이러한 메소드, 프로퍼티. subscript를 subclass만의 버전으로 overriding(오버라이딩) 할 수 있다. Swift는 superclass의 메소드의 선언과 subclass에서 override된 메소드의 선언을 비교하여 올바른지 판별한다.

또한 클래스는 프로퍼티의 값이 변경될 떄 알림을 받기 위해 상속된 프로퍼티에 프로퍼티 옵저버를 추가할 수 있다. 상속받은 프로퍼티 옵저버는 stored property 인지 computed property 인지 상관없이 모든 프로퍼티에 추가가 가능하다.


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

다른 어떤 클래스로부터 상속을 받지 않는 클래스를 base class라고 한다.

NOTE
Objective-C에서는 모든 클래스가 NSObject클래스로부터 파생된 클래스로 생성되는 것과 달리 Swift는 superclass를 지정하지 않으면 자동으로 base class가 된다.

아래 예제는 base class인 Vehicle을 선언하였다. 이 base class는 stored property인 currentSpeed을 선언하고, computed property인 description을 선언하였다. description 프로퍼티는 read-only(getter만 있음)이고 String을 반환한다.

또한 VehiclemakeNoise메소드를 선언하였다. 이 메소드는 실제로 아무 일도 하지 않지만 sublass에서 override 하여 customize 할 수 있다.

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의 새로운 인스턴스를 initializer 구문으로 생성한다.

let someVehicle = Vehicle()

새로운 인스턴스는 description 프로퍼티에 접근할 수 있다.

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

Vehicle클래스는 차량에 대한 공통된 특성을 정의하지만 이 자체로는 많이 사용하지 않는다. 그렇기에, 좀 더 구제척인 차량을 설명할 수 있도록 이것을 상속하는 subclass를 구현해야 한다.


Subclassing (서브클래싱)

Subclassing은 superclass로 부터 새로운 클래스를 만드는 것이다. subclass는 superclass로부터 특성들을 상속받고, 이를 재정의 할 수 있다. 또한 subclass에 새로운 특성을 추가할 수 있다.

subclass가 다른 클래스를 상속하고 있다는 것을 나타내기 위해서 subclass 이름 뒤에 콜론과 superclass이름을 작성한다.

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

다음 예제에서 superclass인 Vehicle를 상속하는 subclass Bicycle를 정의한다.

class Bicycle: Vehicle {
    var hasBasket = false
}

Bicycle클래스는 자동적으로 currentSpeed, description 프로퍼티 그리고 makeNoise()메소드와 같은 Vehicle의 특성을 갖는다.

게다가 subclass인 Bicycle는 새로운 stored property인 hasBasket을 선언하였다.
상속된 프로퍼티인 currentSpeeddescription에 접근하고 수정할 수 있다.

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

또한 subclass는 다른 subclass를 가질 수 있다. subclass인 Bicycle이 다른 클래스에게는 superclass가 될 수 있다.

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}

Tandem 클래스는 부모클래스인 Bicycle클래스의 프로퍼티와 메소드 그리고 조부모인 Vehicle클래스의 프로퍼티와 메소드를 상속한다. 또한 새로운 프로퍼티를 선언할 수도 있다.

아래 예제는 상속받은 모든 프로퍼티와 메소드를 사용하는 예시를 보여준다.

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 (오버라이딩)

Subclass는 superclass의 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티 또는 서브스크립트를 재정의 할 수 있다. 이를 overriding(오버라이딩)이라고 부른다.

이러한 특성들을 override 하려면 override 키워드를 선언의 앞에 작성해야 한다. 실수로 Overriding 하면 예기치 못하 상황이 발생할 수 있고, overide키워드를 생략할 시 컴파일 에러가 발생한다.


Accessing Superclss Methods, Properties, and Subscripts (부모 클래스의 메소드, 프로퍼티 서브스크립트 접근)

Subclass에서 메소드, 프로퍼티, 또는 서브스크립트를 overriding 하는 경우 overriding의 일부로 superclass의 구현 일부를 사용하는 것이 유용할 때가 있다.

superclass의 메소드, 프로퍼티, 서브스크립트에 접근하기 위해서 super키워드를 사용한다.

  • 하위클래스 에서 overridden된 someMethod() 메소드를 접근하는 경우 subclass override 구문 내에서 super.someMethod()처럼 호출한다.

  • 하위클래스 에서 overridden된 someProperty 프로퍼티를 접근하는 경우 override된 getter 또는 setter 내에서 super.someProperty처럼 호출한다.

  • overridden된 someIndex 서브스크립트는 super[someIndex]처럼 호출할 수 있다.


Overriding Methods (오버라이딩 메소드)

상속받은 메소드를 override 하기 위해서 메소드 선언 앞에 override키워드를 붙인다.

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

Train 클래스의 인스턴스를 만들고 makeNoise메소드를 호출하면 Train클래스에서 선언된 버전의 메소드가 호출되는 것을 확인할 수 있다.

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

Overriding Properties (프로퍼티 오버라이딩)

상속받은 인스턴스 또는 타입 프로퍼티를 override하여 custom getter 또는 setter를 생성할 수 있고, overriding된 프로퍼티에 property oberver를 추가할 수 있다.


Overriding Property Getters and Setters (프로퍼티 getter and setter 오버라이딩)

상속받은 프로퍼티가 stored property 또는 computed property 인지 상관없이 override 할 수 있다. Subclass는 상속된 프로퍼티의 이름만 타입만 알고 있기 떄문에 stored property 인지 computed property 인지 알 수 없다. 컴파일러가 Superclass의 프로퍼티와 상속된 프로퍼티의 이름과 타입을 확인하기 떄문에 overriding된 프로퍼티의 이름과 타입을 명시해야 한다.

또한 상속된 read-only 프로퍼티를 read-write 프로퍼티로 subclass에서 override 할 수 있다. 그러나 read-write 프로퍼티를 read-only 프로퍼티로 override 할 수는 없다.

NOTE
상속받은 프로퍼티를 override 할 때 setter를 제공한다면 반드시 getter도 같이 제공해야 한다. 만약 subclass에서 상속받은 프로퍼티에서 getter를 사용하지 않고, setter만 필요한 경우는 getter 구문 내에서 super.someProperty의 값을 반환하면 된다.

다음 예제는 superclass인 Vehicle의 computed property인 descriptionCar 클래스에서 override 하였다. (getter만 override 함)

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

Car 클래스를 만들고 override된 결과가 잘 출력되는 것을 확인할 수 있다.

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 (프로퍼티 옵저버 오버라이딩)

상속된 프로퍼티에 프로퍼티 옵저버를 추가할 수도 있다. 프로퍼티 옵저버를 추가하면 상속받은 프로퍼티가 superclass에서 어떻게 선언되었는지 상관없이 값이 변경될 떄 알림을 받을 수 있다.

NOTE
상속된 상수 stored property나 read-only computed property인 경우 property observer를 추가할 수 없다. 상수 프로퍼티는 는 값을 수정할 수 없고, read-only 프로퍼티는 값이 변경될 일이 없기 떄문이다.

또한 같은 프로퍼티에 overriding된 setter와 overriding property observer를 동시에 제공할 수 없다. setter가 property observer처럼 값의 변화를 알 수 있기 때문이다.

다음은 상속받은 프로퍼티에 property observer를 추가한 예제이다.

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

코드 실행 결과 override된 setter에서 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 (오버라이드 방지)

클래스에 있는 속성들(메소드, 프로퍼티, 서브스크립트)들을 다른 클래스에서 override 하는 것을 방지하기 위해서 final키워드를 사용한다. 그러면 이 superclass를 상속한 subclass에서 final키워드가 붙인 속성을 override 하려고 시도하면 compile-time error가 발생한다.

또한 class에 final키워드를 붙여 클래스 자체를 상속 불가능한 클래스로 만들 수 있다. 이 클래스를 상속하려고 하면 compile-time error가 발생한다.

0개의 댓글