Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

상속 #49

Open
simoniful opened this issue Oct 27, 2022 · 0 comments
Open

상속 #49

simoniful opened this issue Oct 27, 2022 · 0 comments

Comments

@simoniful
Copy link
Owner

simoniful commented Oct 27, 2022

클래스는 다른 클래스로부터 메소드, 프로퍼티 또는 다른 특성을 상속 가능
한 클래스가 다른 클래스를 상속할 때, 상속 받는 클래스를 자식 클래스(서브 클래스, subclass)라 하고,
상속하는 클래스를 부모 클래스(수퍼 클래스, superclass)라고 부른다
상속(inheritance)은 Swift의 다른 타입으로부터 클래스를 차별화하는 중요한 요소

Swift의 클래스는 부모 클래스의 메소드, 프로퍼티, 서브스크립트를 호출하거나 거기에 접근 가능
오버라이딩을 통해 자식 클래스만의 버전으로 재정의할 수 있다
Swift는 오버라이드한 정의가 부모 클래스의 정의와 일치하는지 확인함으로써 오버라이드가 정확한지 보장

클래스는 상속된 프로퍼티에 프로퍼티의 값의 변경 알리기 위한 프로퍼티 옵저버를 설정 가능
프로퍼티 옵저버는 저장 프로퍼티나 계산 프로퍼티에 상관없이 어떤 프로퍼티에도 적용 가능

기반 클래스 정의하기

기반 클래스(base class)는 다른 클래스를 상속하지 않는 클래스

Swift의 클래스는 공통의 기반 클래스를 상속하지 않는다
부모 클래스를 정하지 않은 클래스는 자동적으로 기반 클래스가 된다

class Vehicle {
    // 기본 값이 0.0인 currentSpeed 프로퍼티를 선언
    // 읽기 전용 계산 프로퍼티인 description에서 차량을 묘사하기 위해 사용
    var currentSpeed = 0.0

    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }

    // makeNoise()는 기본 Vehicle 인스턴스에서는 어떤 행동도 하지 않는다
    // Vehicle 클래스의 자식 클래스에서 커스터마이징 가능하도록 구성
    func makeNoise() {
        // do nothing - an arbitrary vehicle doesn't necessarily make a noise
    }
}

// 새로운 Vehicle 인스턴스를 만든 후 
// 차량의 속도를 사람이 읽을 수 있게 묘사하는 description 프로퍼티에 접근 가능
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour

서브클래싱 (Subclassing)

서브클래싱(subclassing)은 기존 클래스를 기반으로 새로운 클래스를 만드는 것
자식 클래스는 기존 클래스로부터 재정의할 수 있는 특성을 상속
새로운 특성을 자식 클래스에 더하는 거도 가능

자식 클래스가 부모 클래스를 가졌다는 것을 알리기 위해,
자식 클래스 이름 뒤에 부모 클래스 이름을 콜론(:)으로 구분하여 넣는다

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

Bicycle 클래스의 예시

// Bicycle 클래스는 자동적으로 Vehicle의 모든 특성을 얻는다
class Bicycle: Vehicle {
    // 상속하는 특성과 더불어, 새로운 저장 프로퍼티인 hasBasket을 정의, 기본값은 false
    var hasBasket = false
}

let bicycle = Bicycle()
bicycle.hasBasket = true

// Bicycle 인스턴스는 상속한 프로퍼티인 currentSpeed를 수정 가능
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour

Tandem 클래스의 예시

// Tandem 클래스 정의
// Vehicle의 메소드와 프로퍼티를 상속을 포함,
// Bicycle의 메소드와 프로퍼티를 상속
class Tandem: Bicycle {
    // 새로운 저장 프로퍼티인 currentNumberOfPassengers를 추가
    var currentNumberOfPassengers = 0
}

// Tandem의 인스턴스 생성
let tandem = Tandem()

// 상속한 Vehicle과 Bicycle의 프로퍼티 접근 가능
tandem.hasBasket = true
tandem.currentSpeed = 22.0

// 새로 만든 프로퍼티에도 역시 접근 가능
tandem.currentNumberOfPassengers = 2

// Vehicle의 읽기 전용인 desciption 프로퍼티에도 접근 가능
print("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour

오버라이딩 (Overriding)

자식 클래스는 부모 클래스로부터 상속한
인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트를 커스터마이징하여 구현 가능
해당 커스터마이징을 오버라이딩(overriding)이라 한다

override 키워드로 오버라이딩을 정의
오버라이드 할 의도를 명확히 하고, 실수에 의해 정의를 매칭하지 않도록 해야 함
잘못된 오버리이딩은 예상치 못한 행동을 유발
override 키워드가 없는 모든 오버라이드는 코드를 컴파일 할 때 에러로 진단

override 키워드는 Swift 컴파일러가 오버라이딩하는 클래스의 부모 클래스를 확인
이러한 체크는 오버라이딩 정의의 정확성을 보장

부모 클래스의 메소드, 프로퍼티, 서브스크립트에 접근하기

자식 클래스에 메소드, 프로퍼티, 서브스크립트를 제공할 때,
오버라이드의 일부분으로써 부모 클래스의 기존 구현을 사용하는 게 유용할 때 사용
ex. 기존 구현의 행위를 재정의할 수 있으며, 수정된 값을 상속한 변수에 저장할 수도 있다

super 접두사를 사용해 부모 클래스의 프로퍼티, 메소드, 서브스크립트에 접근 가능

  • 오버라이드 된 메소드 someMethod()는
    오버라이딩 자식 메소드 안에서 super.someMethod() 메소드를 호출하여someMethod()의 부모 클래스 버전을 사용 가능
  • 오버라이드 된 프로퍼티 someProperty는
    오버라이딩 자식 프로퍼티의 게터/세터에서 super.someProperty를 사용해 someProperty의 부모 클래스 버전에 접근 가능
  • 오버라이드 된 서브스크립트 someIndex는
    오버라이딩 자식의 서브스크립트 구현에서 super[someIndex]를 통해 부모 클래스 버전에 접근 가능

1) 메소드 오버라이딩

자식 클래스 안에서 메소드의 맞춤형 구현을 제공하거나 대체함으로써
상속한 인스턴스 메소드 혹은 타입 메소드를 오버라이딩 가능

// Vehicle의 새로운 자식 클래스인 Train을 정의
class Train: Vehicle {
    // makeNoise() 메소드는 Train에서 오버라이드
    override func makeNoise() {
        print("Choo Choo")
    }
}

// Train의 새로운 인스턴스를 생성
let train = Train()
// makeNoise() 메소드를 호출하면, 자식 클래스 버전의 메소드가 실행
train.makeNoise()
// Prints "Choo Choo"

2) 프로퍼티 오버라이딩

프로퍼티에 커스텀 게터/세터를 제공하거나 프로퍼티 옵저버를 더함으로써
인스턴스 프로퍼티 혹은 타입 프로퍼티를 오버라이드 가능

2 - 1) 프로퍼티 게터/세터 오버라이딩

구현된 프로퍼티가 저장 프로퍼티인지 상속 프로퍼티인지 여부에 상관없이,
상속한 프로퍼티를 오버라이드 하기 위한 커스텀 게터 / 세터를 제공 가능

상속한 프로퍼티의 저장 또는 계산 프로퍼티 여부와 게터 / 세터는 자식 클래스에 알 수 없으며
자식 클래스는 오직 상속한 프로퍼티가 가진 이름과 타입만 알고 있다
오버라이딩 할 때 해당 이름과 타입을 모두 항상 명시 해야
컴파일러가 오버라이드 하는 프로퍼티와 부모 클래스의 프로퍼티가 같은 이름과 타입인지 확인 가능

자식 클래스에서 오버라이드 할 때 게터와 세터를 모두 제공함으로써
읽기 전용 프로퍼티를 읽기/쓰기가 다 가능한 프로퍼티로 상속 가능
하지만, 읽기와 쓰기가 모두 되는 프로퍼티를 읽기 전용 프로퍼티로 상속할 수는 없다

프로퍼티 오버라이드의 일부분으로써 세터를 제공할 경우
반드시 오버라이드를 위한 게터도 제공해야 한다
상속한 프로퍼티의 값을 게터에서 수정하고 싶지 않다면
super.someProperty를 반환하여 간단히 넘겨 버릴 수 있다

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의 새로운 자식 클래스인 Car를 정의
class Car: Vehicle {
    // Car 클래스는 새로운 저장 프로퍼티인 gear를 사용
    var gear = 1
    // Vehicle로부터 description 프로퍼티를 상속해 오버라이드
    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

2 - 2) 프로퍼티 옵저버 오버라이딩

상속한 프로퍼티에 프로퍼티 옵저버를 더하는 오버라이딩이 가능
이렇게 하면 원래 속성이 구현된 방식에 관계없이 상속된 속성 값이 변경될 때 알림을 받을 수 있다

상수 저장 프로퍼티나 읽기 전용 계산 프로퍼티를 오버라이드 한 경우
프로퍼티 옵저버를 더할 수 없다
이런 프로퍼티의 값을 설정할 수 없기에,
오버라이드의 일부분으로써 willSet이나 didSet을 제공하지 못하기 때문

같은 프로퍼티에 오버라이딩 세터와 오버라이딩 프로퍼티 옵저버를 둘 다 작성은 불가
만약 프로퍼티 값의 변화를 관찰하고자 하는데
이미 프로퍼티에 커스텀 세터를 제공 중이라면
커스텀 세터 안에서 값의 변화를 관찰 가능

// Car의 새로운 자식 클래스인 AutomaticCar를 정의
class AutomaticCar: Car {
    override var currentSpeed: Double {
        // 자동 변속 장치가 장착된 자동차를 나타내며, 현재 속도에 따라 사용할 적절한 기어가 자동으로 선택
        // currentSpeed 프로퍼티를 설정할 때마다
        // didSet 관찰자는 인스턴스의 기어 프로퍼티를 새로운 속도에 적합한 기어 선택으로 설정
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}

let automatic = AutomaticCar()
// 속도가 35.0이면 4단 기어가 생성
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4

오버라이드 방지

final 키워드를 사용해 메소드, 프로퍼티, 서브스크립트가 오버라이드 되는 것을 방지 가능
ex. final var, final func, final class func, and final subscript와 같이 작성
final로 선언된 메소드, 프로퍼티, 서브스트링을 오버라이드 하려고 시도하면 컴파일 에러가 발생
클래스 전체를 final로 선언해서 클래스 안의 모든 메소드, 프로퍼티 등이 override가 되는 것을 막는 것도 가능

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant