Notice
Recent Posts
Recent Comments
Link
大器晩成
재정의(오버라이딩) - 메서드 본문
메서드의 재정의
- 상위 클래스 인스턴스 메서드 또는 타입 메서드 상관없이 기능을 추가하는 것도 가능합니다.
- 오버라이딩 대상이 되는 메서드의 매개변수 개수나 타입, 그리고 반환타입은 변경할 수가 없습니다.
- 상위 클래스에서 정의된 메서드의 반환 타입이 String이었다면 오버라이딩된 메서드 역시 반환 타입을 String으로 유지해야 합니다.
- 클래스에서 메서드의 매개변수가 String, Int 두 개였다면 오버라이딩 된 메서드에서도 매개변수는 여전히 String, Int 두 개여야 하며, 순서도 변경해서는 안됩니다.
- 메서드 오버라이딩을 통해 변경할 수 있는 것은 오로지 내부 구문들 뿐입니다. 매개변수 타입이나 반환타입은 반드시 그대로 유지해야 합니다.
class Warrior {
var job: String = "전사"
var gender : String = "남"
var items: [String] = ["낡은가죽바지", "두손도끼", "한손검"]
func evolution() {
print("전사로 전직했습니다.")
}
subscript(index: Int) -> String {
get {
if index > 2 {
return "아이템이 없습니다."
}
return items[index]
}
set {
items[index] = newValue
}
}
}
1. 상위 메서드를 하위 메서드에서 호출
class Hero: Warrior {
override func evolution() {
print("히어로로 전직했습니다.")
}
}
let user = Hero()
user.evolution()
// result
전사로 전직했습니다.
히어로로 전직했습니다.
- 하위 클래스에서 상위 클래스의 함수 호출 가능
2. 하위 메서드 실행 후 상위 메서드 호출
class Hero: Warrior {
override func evolution() {
print("히어로로 전직했습니다.")
super.evolution()
}
}
let user = Hero()
user.evolution()
// result
히어로로 전직했습니다.
전사로 전직했습니다.
3. 상위 구현 무시
class Hero: Warrior {
override func evolution() {
print("히어로로 전직했습니다.")
}
}
let user = Hero()
user.evolution()
// 출력: 히어로로 전직했습니다.
- 상위 기능을 무시하고 새롭게 구현하는 것도 가능합니다.
(제약 없음 - 메서드 이름만 동일하고 완전히 새롭게 구현 가능하다고 생각하면 됩니다.) - 다만, 기능을 추가하는 구현을 선택할 시에 상위구현의 기능을 먼저 실행할지의 여부는 개발자의 선택입니다.
4. 서브스크립트 재정의
class Hero: Warrior {
override func evolution() {
print("히어로로 전직했습니다.")
}
override subscript(index: Int) -> String {
get {
if index > 2 {
return "전설급아이템."
}
return super[index]
}
set {
super[index] = newValue
}
}
}
let user = Hero()
user[0] = "바지"
user[3] // 낡은 가죽 바지
자식클래스에서 값을 바꿨다고 해서 user2의 Warrior에 영향을 미치는 것은 아니다. (서로 독립적인 공간)
let user2 = Warrior()
user2[0] // 낡은 가죽 바지
// 타입 캐스팅을 통한 변경된 값 확인
// (이때, 타입캐스팅한 Warrior랑 User2의 Warrior는 전혀 다른 객체이다)
(user as Warrior).items[0] // 바지
- 상위의 서브스크립트를 구현했기 때문에, 대괄호가 사용이 가능합니다.
- 그래서 하위에서 구현할 때는 super[Index] 사용하면 상위 클래스에 정의된 subscript 메서드를 호출한다.
- 서브스크립트 구문에서 값을 읽거나 쓰는 items 속성은 상위 클래스에 저장되어 있습니다. 그렇기 때문에, 하위 클래스에서는 처리할 수 없습니다. (저장속성은 저장속성으로 재정의가 불가능)
- 상위 서브스크립트를 호출함으로써, 값을 변경할 수 있습니다.
5. super[Index] vs super.dates[Index]
class A {
var datas = ["1", "2", "3", "4", "5"]
subscript(index: Int) -> String {
get {
if index > 4 {
return "0"
}
return datas[index]
}
set {
datas[index] = newValue
}
}
}
class B: A {
override subscript(index: Int) -> String {
get {
if index > 4 {
return "777"
}
return super[index] // 부모 클래스의 서브스크립트를 호출
}
set {
super[index] = newValue // 부모 클래스의 서브스크립트에 값을 설정
}
}
func subscriptTest() {
// super[index]는 부모 클래스의 서브스크립트를 호출합니다.
print(super[2]) // "3"이 출력됨 (datas[2]는 "3"이라서)
super[2] = "99" // 부모 클래스 서브스크립트를 통해 "99"로 값 설정
print(datas) // ["1", "2", "99", "4", "5"] (datas[2]가 "99"로 변경됨)
// super.datas[index]는 부모 클래스의 datas 배열에 직접 접근
print(super.datas[2]) // "99"가 출력됨 (datas[2]는 이제 "99")
}
}
let sub = B()
sub.subscriptTest()
- super[index]는 부모 클래스의 서브스크립트를 호출합니다.
- 서브스크립트 문법을 사용하여 부모 클래스에서 정의한 서브스크립트 호출하는 것으로 부모 클래스에 정의된 subscript 메서드를 실행합니다 - super.datas[index]는 부모 클래스의 datas 배열에 직접 접근합니다.
- 배열에 직접 접근하는 것은 서브스크립트 문법을 사용하는 것이 아닙니다. 즉, dates 배열의 특정 인덱스에 접근하는 것입니다. 이는 서브스크립트와는 별도로 배열의 값에 직접 접근하는 방식입니다.
참고사항
- 메서드의 경우에는 오버라이딩 제약 조건으로 매개변수 타입이나 반환 타입을 그대로 유지해야 하는 이유는 스위프트가 메서드 오버로딩(Overloading)을 지원하기 때문입니다. 이때, 기준이 되는 것이 매개변수의 타입과 종류입니다. 즉 같은 이름의 메서드라도 정의된 매개변수의 타입이 다르면 서로 다른 메서드를 처리하는 것이 오버로딩입니다.
func makeNoise()
func makeNoise(param: Int)
func makeNoise(param: String)
func makeNoise(param: Double) -> String
func makeNoise(param: Double, append: String)
func makeNoise(param: Double, appendix: String)
- makeNoise의 예를 살펴보면 이 메서드는 다음과 같이 하나의 이름으로 된 여러 개의 메서드로 정의될 수 있습니다.
물론 이들 메서드는 컴파일러에 의해 서로 다른 메서드로 처리됩니다.. - 스위프트에서 메서드는 이름뿐만 아니라 매개변수의 개수와 타입을 기준으로 하여 유일성 여부를 구분합니다.
- 따라서 이름이 같고 매개변수의 개수까지 일치하더라도 타입이 다르면 서로 다른 메서드로 간주합니다.
- 매개변수명까지 메서드의 정의에 포함되므로 매개변수의 개수, 타입이 모두 일치하여도 매개변수명이 다르면 새로운 메서드로 정의됩니다.
- 같은 메서드 이름이지만 매개변수의 변화만으로 새로운 메서드를 만들어 적재할 수 있도록 지원하는 문법이 오버로딩입니다.
오버라이딩과 오버로딩 구분
- 오버라이딩을 덮어쓰기라는 개념으로 정의하는 것이 좀 더 직관적일 수 있습니다.
- 오버라이딩된 메서드나 프로퍼티는 해당 클래스를 상속받는 모든 자식 클래스에 적용됩니다.
- 적용된 자식 클래스를 다시 서브클래싱했을 때도 마찬가지입니다. 하지만 부모클래스는 오버라이딩 영향을 받지 않습니다.
- 물론 부모 클래스를 상속받은 다른 형제뻘 클래스들도 오버라이딩 된 메서드나 프로퍼티는 적용되지 않습니다.
// 하나는 프로퍼티를 오버라이딩한 Car 클래스를 상속받고,
// 또 다른 하나는 기본 클래스인 Vehicle을 상속받습니다.
// 두 가지 클래스를 각각 서브클래싱한 결과가 어떻게 다른지 확인해봅시다.
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "시간당 \(self.currentSpeed)의 속도로 이동하고 있습니다."
}
func makeNoise() {
}
}
class Car: Vehicle {
var gear = 0
var engineLevel = 0
override var currentSpeed: Double {
get {
return Double(self.engineLevel * 50)
} set {
super.currentSpeed = newValue
}
}
override var description: String {
get {
//print("슈퍼: \(super.currentSpeed) ")
return "Car : engineLevel = \(self.engineLevel), so currentSpeed = \(self.currentSpeed)"
} set {
print("New Value is \(newValue)") //descrpition. 프로퍼티에 값을 할당하면 set 구문이 실행
}
}
}
class HybridCar : Car {
// 아무것도 추가로 선언하지 않음
}
class KickBoard : Vehicle {
// 아무것도 추가로 선언하지 않음
}
let h = HybridCar()
//h.engineLevel = 40
//h.currentSpeed = 20
h.description //"Car : engineLevel = 0, so currentSpeed = 0.0
let k = KickBoard()
k.description //"시간당 0.0의 속도로 이동하고 있습니다."
- Car를 상속받는 HybridCar는 Vehicle과 Car의 메서드 및 프로퍼티를 상속받고 있습니다.
- Vehicle을 상속받는 KickBoard는 Vehicle의 메서드와 프로퍼티만 상속받고 있습니다.
- 공통된 부모클래스를 사용한다고 해도, 어떤 클래스를 상속받냐에 따라 자식클래스가 가질 수 있는 프로퍼티와 메서드의 차이가 발생합니다.
728x90
'iOS > Swift 문법' 카테고리의 다른 글
지정생성자와 편의생성자 (0) | 2024.11.28 |
---|---|
초기화(Initialization)와 생성자(Initializer) (0) | 2024.11.27 |
재정의(오버라이딩,Overriding) - 속성(프로퍼티) (0) | 2024.11.26 |
클래스의 상속 (Inheritance) (0) | 2024.11.25 |
구조체와 클래스(let, var) 참고자료 (0) | 2024.11.25 |