아아.. 이번 글은 확신은 없어요..
혹시 누군가 보게 된다면 참고정도만 해주시길 🥲
아래 예시를 보자
class 부모타입 {
func printF() {
print("나는 부모")
}
}
class 자식타입: 부모타입 {
override func printF() {
print("나는 자식")
}
}
let child = 부모타입()
let parent = temp as 부모타입 // 부모타입으로 타입캐스팅
parent.printF() // "나는 자식"...?!?!
위와 같이 메서드를 override하게 되면 그와 대응되는 super의 정보는 필요없다고 판단하여 저장하지 않으므로, 타입캐스팅을 한다고 해서 부모의 메서드를 사용할 수 있는게 아닙니다
출처
class 자식타입: 부모타입 {
public func printF() { // OK. no Error
print("나는 자식")
}
}
멤버인 printF()
메서드에 public을 주었지만 사실은 internal로 적용된다
우선 override 메서드의 접근제어 rule은 다음과 같다
- override 메서드의 access level은 부모의 원본메서드보다는 약해야 합니다
- 단, 자식타입 자체의 level이 부모의 원본메서드보다 강하다면 자식타입 자체 level까지는 가능합니다
즉, Override 메서드의 접근제어 제약은 부모의 원본메서드
와 자식타입 자체
의 Access level에 의해 결정됩니다
2번 이해가 어려울 것 같아 예시를 들면 이런게 가능합니다
아래 예제에서
원본메서드(internal)보다 override메서드(fileprivate)가 더 강하므로 1번 룰에 의해 일반적으론 안되지만,
타입 자체(자식타입)가 fileprivate이어서 override메서드도 fileprivate까지는 가능해집니다
class 부모타입 {
func printF() {
print("나는 부모")
}
}
fileprivate class 자식타입: 부모타입 {
override fileprivate func printF() {
print("나는 자식")
}
}
도대체 왜일까?
일반 메서드는 상관없는데 override 메서드에만 왜 이리 엄격한 것일까
완전히 이해되진 않지만, 나중에 다시 보고자 어떤 분의 답변을 정리해본다
위 말을 정리해보면
포스팅의 처음에 말했던대로 override당한 메서드의 super버전은 자식 인스턴스에 저장되지 않으므로, 타입캐스팅이든 어떤 방식이든 자식 인스턴스로부터 super버전을 불러올 수는 없다
이를 염두에 두고,
(일부러 룰을 위반한) 아래 코드가 만약 컴파일 에러를 유발하지 않는다면, 어떤 문제가 발생할 수 있는지 다시 생각해보자
(실험을 위해 파일 두 개로 구현하였다)
// definition.swift
class 부모타입 {
func printF() {
print("나는 부모")
}
}
class 자식타입: 부모타입 {
override fileprivate func printF() {
print("나는 자식")
}
}
// experiment.swift 파일
let child = 자식타입()
let parent = child as 부모타입()
parent.printF() // ?!?!
parent가 부모타입으로 캐스팅되었지만 원본은 자식타입이므로
parent.printF()
는 자식타입의 것을 호출하게 됩니다
하지만, 해당 메서드는 experiment.swift
에서는 접근할 수 없는 fileprivate 권한이므로 당연히 호출이 불가합니다
여기서 타입캐스팅과 맞물려,
부모타입의 printF()가 internal이므로 이를 호출할 수 있을 것만 같은 착각을 유발합니다
(실제로는 이 인스턴스에는 자식타입의 printF()만 들어있어서 여기선 printF() 메서드를 사용할 수 없는데 말이죠)
이를 막기 위해 컴파일 에러를 유발한다고 합니다..
뭔 말일까.. 이쯤되면 그냥 외울까싶다..
추가 의견
Stackoverflow
무슨 말일까...