[Swift] 11. 상속(Inheritance)과 재정의(Override)

Hoojeong Kim·2022년 3월 9일
0

Swift Base

목록 보기
13/22
post-thumbnail

상속

상속이란 일반적으로 부모가 자신에게 재산을 물려주는 행위이다. 스위프트에서의 상속은 클래스가 다른 클래스로부터 메서드, 프로퍼티 등을 물려받는 것을 말한다.
어떤 클래스에게 자신의 특성을 물려준 클래스를 부모클래스, 슈퍼클래스 라고 하며, 물려받은 클래스를 자식클래스, 서브클래스 라고 한다. 이때, 상속을 받지 않은 클래스를 베이스클래스 라고 한다.

자식클래스는 부모클래스로부터 물려받은 메서드를 호출하거나 프로퍼티에 접근하는 것이 가능하며, 이를 자신만의 내용으로 재정의할 수 있다. 또한 상속받은 프로퍼티에 값이 변경되었을 때 알려주는 프로퍼티 옵저버도 구현할 수 있다.


먼저 앞으로 구현할 클래스의 부모가 될 클래스를 구현하자.
class Vehicle {
	var currentSpeed = 0.0
    var description: String {
    	return "traveling at \(currentSpeed) miles per hour"
    }
    
    func makeNoise() {
    
    }
}

이어서 자식클래스를 구현하기 위해서는 클래스 이름 뒤에 부모클래스 이름을 작성해 나타낼 수 있다.
class 클래스 이름: 부모클래스 이름 {
	프로퍼티와 메서드들
}

위와 같은 방식으로 생성한 Vehicle 클래스로부터 상속받을 자식 클래스를 구현해보자.
class Bicycle: Vehicle {
    var hasBasket = false
}

var bicycle = Bicycle()
bicycle.currentSpeed = 15.0
print(bicycle.currentSpeed)
15.0

자식클래스에는 현재 hasBasket 프로퍼티밖에 없지만, Vehicle 클래스로부터 상속받았기 때문에 위처럼 부모클래스의 프로퍼티나 메서드를 사용할 수 있다.

오버라이딩

자식클래스는 부모클래스로부터 상속받은 메서드나 프로퍼티 등을 그대로 사용하지 않고 자신만의 기능으로 변경하여 사용할 수 있다. 이를 바로 재정의, 오버라이드 라고 한다.

상속받은 특성들을 오버라이딩 하기 위해서는 맨 앞에 override 키워드를 사용한다. 해당 키워드는 스위프트 컴파일러가 조상클래스(부모 포함 상위 부모클래스)에 해당 프로퍼티나 메서드 등이 있는지 확인한 후 재정의 한다.

이때 만약 조상클래스에 해당 특성이 없다면, 컴파일 에러가 발생한다.

메서드 오버라이딩

그렇다면, 앞에서 구현한 Vehicle의 makeNoise() 메서드를 오버라이딩 해보자.

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

let train = Train()
train.makeNoise()
choo choo

출력 결과를 보면, Vehicle 클래스를 상속받은 Train 클래스에서 상속받은 makeNoise() 메서드를 오버라이드한 결과가 호출된 것을 알 수 있다.

super

만약 자식클래스에서 부모클래스의 프로퍼티나 메서드를 오버라이드한 뒤, 부모클래스의 프로퍼티나 메서드를 사용하고 싶다면 어떻게 해야 할까?
이때 사용하는 것이 바로 super 키워드이다.


먼저 부모클래스인 Vehicle의 makeNoise() 메서드에 코드를 추가하자.
class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    
    func makeNoise() {
        print("speaker On")
    }
}

이어서, 자식클래스에서 부모클래스의 makeNoise()와 오버라이드한 makeNoise()를 사용해보자.
class Train: Vehicle {
    override func makeNoise() {
    	super.makeNoise()
        print("choo choo")
    }
}

let train = Train()
train.makeNoise()
speaker On
choo choo

이처럼 super 키워드를 사용하면 내가 메서드를 오버라이드 했더라도, 부모클래스의 메서드를 그대로 가져와 사용할 수 있다.

프로퍼티 오버라이딩

다음으로 프로퍼티를 오버라이딩 해보자.
프로퍼티를 오버라이딩한다는 것은 프로퍼티 자체가 아닌, 프로퍼티의 getter, setter, 옵저버 등을 오버라이딩하는 것을 의미한다.


그렇다면, 코드로 확인해보자.
class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}

let car = Car()
car.currentSpeed = 30.0
car.gear = 2
print(car.description)
traveling at 30.0 miles per hour in gear 2

이렇게 부모클래스에 있는 프로퍼티 getter도 자식클래스에서 오버라이딩할 수 있다.


추가로, 부모클래스에서 읽기 전용 프로퍼티이더라도 자식클래스에서 읽기, 쓰기가 모두 가능한 프로퍼티로 오버라이딩할 수 있다. 하지만 읽기, 쓰기가 모두 가능한 프로퍼티를 읽기 전용 프로퍼티로 오버라이딩할 수는 없다.
읽기 전용 프로퍼티   -->   읽기, 쓰기 프로퍼티  (가능)
읽기, 쓰기 프로퍼티  -->   읽기 전용 프로퍼티   (불가능)

이번에는 프로퍼티 옵저버를 구현해보자.
class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10) + 1
        }
    }
}

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

이처럼 currentSpeed의 값이 변경된 직후에 오버라이딩한 didSet 메서드가 실행된 것을 알 수 있다.

추가로, 상수로 정의된 프로퍼티나 읽기 전용 프로퍼티는 값을 설정할 수 없기 때문에 프로퍼티 옵저버를 오버라이딩할 수 없다.

오버라이딩 방지

마지막으로, 부로클래스를 상속받는 자식클래스에서 몇몇 특성을 오버라이딩할 수 없도록 제한하고자 할 때는 final 키워드를 사용한다. 프로퍼티나 함수, class 앞에 final 키워드를 명시하여 구현한다.

class Vehicle {
    final var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    
    func makeNoise() {
        print("speaker On")
    }
}

만약 위처럼 부모클래스인 Vehicle의 currentSpeed 프로퍼티 앞에 final 키워드를 명시한다면, 오버라이딩하여 currentSpeed 프로퍼티를 사용하는 모든 자식클래스에서 컴파일 에러가 발생한다.

profile
나 애기 개발자 👶🏻

0개의 댓글