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

[Swift] Override #6

Closed
ujhong7 opened this issue Mar 15, 2024 · 0 comments
Closed

[Swift] Override #6

ujhong7 opened this issue Mar 15, 2024 · 0 comments

Comments

@ujhong7
Copy link
Owner

ujhong7 commented Mar 15, 2024

오버라이딩


메서드 오버라이딩?

상속받은 인스턴스&타입 메서드를 재정의하여, 하위클래스 내에서 해당 메서드를 원하는 대로 구현할수있다.

class Human {
	func description() {
		print("사람입니다.")
	}
}

class Student: Human {
}
let hong: Student = .init()
hong.description() // 사람입니다.

Student 클래스 인스턴스로 description이란 메서드에 접근에 접근하면 “사람입니다.” 가 실행됨

“학생입니다.”를 출력되게 하려면

class Student: Human {
	override func description() {
		print("학생입니다.")
	}
}

이렇게 override 키워드를 붙여주면 오버라이드, 즉 ‘재정의’가 가능함.

let hong: Student = .init()
hong.description() //  학생입니다.

오버라이딩(재정의)된 메서드는 슈퍼클래스에서 작성된 메서드가 실행되지 않고 재정의 한 메서드가 실행됨.

오버라이딩(재정의)이란 슈퍼 클래스의 메서드를 재정의해서 사용할 수 있다.

오버라이딩 메서드를 작성한 서브 클래스에서 슈퍼 클래스의 메서드를 사용하고싶으면?

class Student: Human {
	override func description() {
		super.description() // 사람입니다.
	}
}

super를 사용하면, 슈퍼 클래스에 접근할 수 있다.

이렇게 슈퍼 클래스의 메서드도 오버라이딩 된 메서드도 모두 실행 가능함.

주의할점? (추가필요…)

동기(sync)한 환경에서 코드의 실행순서는 LIFO이기 때문에,

class Student: Human {
	override func description() {
		print("학생입니다.") 
		super.description() // 사람입니다.
	}
}

이렇게 super를 마지막에 불러주면 당연히 마지막에 실행된다.

→ 슈퍼클래스의 메서드를 부르는 작업을 꼭 맨처음에 해야하는 것은 아니다.

override란 키워드를 붙이면 컴파일러는 해당 정의가 슈퍼 클래스에 있는지 확인하는 작업을 함.

(오버라이딩이 맞는지 아닌지)

존재하지 않는 메서드에 override란 키워드를 붙이면 에러발생함.

프로퍼티 오버라이딩?

상속받은 프로퍼티를 오버라이딩하여 해당 속성에 대한 getter, setter를 제공하거나,

상속받은 프로퍼티 값의 변경을 추적할 수 있도록 옵저버를 추가함.

→ 프로퍼티를 오버라이딩 한다는 것은 getter, setter를 추가할 수 있다.

즉, ‘연산 속성’을 추가할 수 있고 프로퍼티 옵저버를 추가할 수 있다..


연산 속성 추가하기

프로퍼티를 오버라이딩 할려면 ‘프로퍼티 이름’과 ‘타입’을 반드시 명시해야함.

저장 프로퍼티

프로퍼티의 경우 ‘연산’ 속성을 추가하는 것만 가능함..

저장 프로퍼티에 ‘저장’ 속성을 추가하는 오버라이딩이 가능할까?

class Human {
	var name = "Hong"
}

class Student: Human {
	override var name: String = "Hong2" // ❌ 에러
}

안됨!

그렇다면 상속받은 저장 프로퍼티에 ‘연산’ 속성인 get, set을 추가하는 오버라이딩은 가능할까?

class Student: Human {
	var alias = "HHong"
	
	override var name: String { // ❌ 에러
		return self.alias
	}
}

read-only 프로퍼티로 오버라이딩 할 수 없음.

무슨말이냐..

슈퍼클래스 Humane클래스에서 name이란 프로퍼티는 ‘저장 프로퍼티’여서

기본적으로 getter와 setter가 모두 제공되는 읽기&쓰기가 가능한 프로터티임.

그런데 Student란 서브 클래스에서 name이란 프로퍼티는 getter만 가능하게 오버라이딩 해버리니까 ‘읽기/쓰기 모두 가능한 애인데 왜 서브 클래스 너가 읽기만 가능하게 제한을 둠?’ 하고 에러가 나는거.

따라서, 저장 프로퍼티를 오버라이딩 하고 싶다면,

class Student: Human {
	var alias = "HHong"
	
	override var name: String {
		get {
			return self.alias
		}
		set {
			self.alias = newValue
		}
	}
}

이렇게 getter / setter 를 모두 구현해주면 오버라이딩이 된다.

let student: Student = .init()
student.name // HHong

실행해보면 오버라이딩 된 alias의 값인 “HHong”이 나오는걸 볼 수 있다.

연산 프로퍼티

저장 프로퍼티의 경우 getter / setter가 이미 구현되어 있는데..

오버라이딩 해서 getter만 구현하는 것은 안된다고 했는데

연산 프로퍼티 또한 마찬가지

class Human {
	var name = "Hong"
	
	var alias: String {
		return self.name + "노움"
	}
}

이렇게 Human 클래스에 alias라는 연산 프로퍼트가 getter로만 구현된 경우

class Student: Human {
	override var alias: String {
		return self.name + "안녕"
	}
}
class Student: Human {
	override var alias: String {
		get {
			return self.name + " 안녕"
		}
		set {
			self.name = newValue
	}
}

서브클래스에서 위와 같이 getter만 구현 하거나 setter를 추가 구현하는 오버라이딩이 가능

하지만, 연산 프로퍼티가 getter / setter 로 구현된 경우, 서브클래스에서 getter만 구현하는 오버라이딩은 안됨.

class Student: Human {
	override var alias: String { // Cannot override mutable property
		return self.name + " 안녕" // ❌
	}
}

프로퍼티 옵저버 추가하기

저장 프로퍼티의 경우, var로 선언된 프로퍼티만 오버라이딩으로 옵저버를 추가할 수 있음.

연산 프로퍼티의 경우, getter / setter 가 모두 구현된 경우만 오버라이딩으로 옵저버를 추가할 수 있음.

프로퍼티 옵저버 TIL 작성 후 링크 달기..

저장 프로퍼티

var로 선언된 경우만 가능

프로퍼티 옵저버의 경우 “값이 변경”될 때를 알려주는 것..

상수(let)이면 값이 바뀔 일 없기 때문에 쓸 이유가 없음.. → 변수(var)일 때만 가능

class Human {
	var name = "Hong"
}

class Student: Human {
	override func name: **String** {
		willSet {
			print("name 값 변경될꺼임. \(newValue)")
		}
		didSet {
			print("name 값 변경됐다. \(oldValue)")
		}
	}
}

이렇게 슈퍼 클래스의 변수 저장 프로퍼티를 서브클래스에서 오버라이딩 해서 프로퍼티 옵저버를 추가할수있음.

let student: Student = .init()
student.name = "노움"

// name 값 변경될꺼임. 노움
// name 값 변경됐다. Hong

오버라이딩해서 추가한 프로퍼티 옵저버가 잘 동작함.

주의!

컴파일러는 이 alias가 오버라이딩 되는 게 맞는지 확인하기 위해서

프로퍼티를 오버라이딩시에는 “프로퍼티 이름”, “타입”이 반드시 명시되어야함!

override func name: **String** { ... }

슈퍼클래스의 프로퍼티가 타입 추론에 의해 타입이 명시 되어 있지않아도

프로퍼티를 오버라이딩 할 경우엔 타입을 반드시 명시해야함

안하면 타입 명시하라고 에러남.

연산 프로퍼티

getter만 구현된 경우 setter(값변경)이 호출될일 없음 → 옵저버를 왜 붙임?

→ getter / setter 가 모두 구현된 연산 프로퍼티만 프로퍼티 옵저버를 붙일 수 있음..

class Human {
	var name = "Hong"
	
	var alias: String {
		get {
			return name + " 안녕"
		}
		set {
			self.name = newValue
		}
	}
}
class Student: Human {
	override var alias: String {
		willSet {
			print("연산 프로퍼티 실행될거임")
		}
		didSet {
			print("연산 프로퍼티 실행됐다")
		}
	}
}

실행해보면..

let student: Student = .init()
student.alias = "노움"

// 연산 프로퍼티 실행될거임
// 연산 프로퍼티 실행됐다

잘 동작함.


오버라이딩 금지! final

오버라이딩이 가능한 프로퍼티, 메서드, 서브스크립트 등에 final 키워드를 붙이면 더이상 오버라이딩이 불가능함.

class Human {
	**final** var name = "Hong"
	**final** func description() {
		print("홍홍홍")
	}
}

이렇게 final 키워드를 붙이면..

class Student: Human {
	override func name: String { ... // ❌ Property overrides a 'final' property
}
class Student: Human {
	override func description() { ... // ❌ Instance method overrides a 'final instance..
}

서브 클래스에서 오버라이딩 불가능함..

final을 붙인다고 오버라이딩이 금지된 것이지 접근자체가 금지된거는 아님!!!

let student: Student = .init()
student.name
student.description()

final이 붙어도 서브클래스에서 접근가능

@ujhong7 ujhong7 changed the title [Swift] Overriding [Swift] Override Mar 15, 2024
@ujhong7 ujhong7 mentioned this issue Mar 17, 2024
@ujhong7 ujhong7 closed this as completed Mar 17, 2024
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