Inheritance
class Hierarchy
상속관계에 있는 클래스들은 클래스 계층을 구성
클래스 계층에서 가장 위에있는 클래스를 Root Class, Base Class라고 함
바로 아래에 있는 클래스는 Base Class를 상속 받고 상속관계에서 위에 있는 클래스를 Parent Class, Super Class라고 함
아래있는 클래스는 Child Class, SubClass 라고 함
Base Class아래에는 하나이상의 SubClass가 존재하지만 위쪽에는 Super Class 존재하지 않음
여러 SubClass가 공통적인 하나의 Super Class를 상속하는 것은 문제가 없음
2개 이상의 Super Class를 상속받는 것은 불가능 (Multiple Inheritance(다중상속))
Inheritance
class ClassName : SuperClassName {
}
서브클래스는 슈퍼클래스로부터 맴버를 상속 받음
class Figure {
var name = "Unknown"
inti(name : String) {
self.name = name
}
func draw() {
print("draw" \(name)")
}
}
class Circle : Figure {
var radius = 0.0
}
let c = Cirecle(name : "Circle")
c.radius
c.name
c.draw()
Final class
모든 클래스는 상속의 대상이 될 수 있으나 경우에 따라 상속을 금지할 때 사용
final class ClassName : SuperClassName {
}
Rectangle클래스가 다른 클래스를 상속받는건 가능하지만 다른 클래스가 Rectangle클래스를 상속하는 건 금지
final class Rectangle : Figure {
var width = 0.0
var height = 0.0
}
class Square : Rectangle { // Error
}
Overriding
subclass에서 superclass와 동일한 맴버를 구현하는 것
methods, properties, subscripts, initializers 가능
- 상위 구현을 무시하고 새로운 구현할 때 override 사용
class Figure {
var name = "Unknown"
init (name : String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
class Circle : Figure {
var radius = 0.0
override func draw() {
print("hi")
}
}
let c = Cirecle(name : "Circle")
c.draw() // "hi"
- 상위 구현을 기반으로 구현할 때 super사용
class Figure {
var name = "Unknown"
init (name : String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
class Circle : Figure {
var radius = 0.0
override func draw() {
super.draw()
print("hi")
}
}
let c = Cirecle(name : "Circle")
c.draw() // draw Circle, hi
- 속성을 override 하는 경우 계산속성, 속성 옵저버 사용 아래 예시는 계산속성을 사용하여 override 하는 예시
읽기 전용 속성을 읽기와 쓰기가 가능한 속성으로 overriding 하는 것은 허용되나 읽기나 쓰기가 가능한 속성을 읽기 전용으로 overriding 하는 것은 허용되지 않음
overriding 에서 super를 self로 쓸 경우 오류가 발생하고 찾기도 힘드니 실수를 조심
class Figure {
var name = "Unknown"
init (name : String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
class Circle : Figure {
var radius = 0.0
var diameter : Double {
return radius * 2
}
override func draw() {
super.draw()
print("hi")
}
}
let c = Cirecle(name : "Circle")
c.draw() // draw Circle, hi
class Oval : Circle {
override var diameter : Double {
get {
return super.diameter
}
set {
super.radius = newValue / 2
}
}
override var radius : Double {
get {
return super.radius
}
set {
super.radius = newValue
}
}
}
- 아래 예시는 속성옵저버를 사용하여 override 하는 예시
읽기전용 속성의 경우 속성 옵저버를 사용할 수 없음, 읽기전용 속성의 경우 값이 바뀌지 않는데 속성옵저버를 사용할 수 없음
변수저장 속성에서만 지원됨
class Figure {
var name = "Unknown"
init (name : String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
class Circle : Figure {
var radius = 0.0
var diameter : Double {
return radius * 2
}
override func draw() {
super.draw()
print("hi")
}
}
let c = Cirecle(name : "Circle")
c.draw() // draw Circle, hi
class Oval : Circle {
override var diameter : Double {
get {
return super.diameter
}
set {
super.radius = newValue / 2
}
}
override var radius : Double {
willSet {
print(newValue)
}
didset {
print(oldValue)
}
}
}
override를 금지하기 위해서는 앞에 final을 붙여주면 됨
상속대상에서 제외되는 것은 아님, 접근은 가능
class Figure {
var name = "Unknown"
init (name : String) {
self.name = name
}
final func draw() {
print("draw \(name)")
}
}
class Circle : Figure {
final var radius = 0.0
var diameter : Double {
return radius * 2
}
override func draw() { // Error
super.draw()
print("hi")
}
}
let c = Cirecle(name : "Circle")
c.draw() // draw Circle, hi
class Oval : Circle {
override var diameter : Double {
get {
return super.diameter
}
set {
super.radius = newValue / 2
}
}
override var radius : Double { // Error
willSet {
print(newValue)
}
didset {
print(oldValue)
}
}
}
let o = Ovarl(name : "Oval")
o.radius
Upcasting & Downcasting
subclass 인스턴스를 슈퍼클래스 형식으로 저장하는 것을 Upcasting
square 인스턴스를 생성할 경우 name, width, height를 저장할 수 있는 공간이 생성 해당 인스턴스를 Figure 클래스로 Upcasting할 경우 Figure 클래스에 선언된 맴버로 접근 범위가 제한 -> 실제로는 width, height 속성이 메모리에 저장되어있지만 Figure 클래스가 인식할 수 있는 name 속성에만 접근가능
동일한 클래스에서 수행된 Upcasting은 안전함 하지만 Downcasting은 불안전
Square 클래스는 Figure 클래스로 Upcasting 되어있고 Rectangle 클래스는 Square 클래스의 SuperClass 동시에 Rectangle 클래스는 Figure 클래스 SubClass
Upcasting된 클래스의 SubClass 면서 원본 클래스의 SuperClass로 Downcasting하는 것도 가능
원본클래스보다 아래쪽에 있는 SubClass로 다운케스팅은 안됨
class Figure {
let name : String
init(name : String) {
}
func draw() {
print("draw \(name)")
}
}
class Rectangle : Figure {
var width = 0.0
var hegight = 0.0
override func draw() {
super.draw()
print("\(width) x \(height)")
}
}
class Square : Rectangle {
}
let f = Figure(name : "Unknown")
f.name
let r = Rectangle(name : "Rect")
r.width
r.height
r.name
let s : Figure = Square(name: "Square")
s.width // Error
s.height // Error
s.name
// Downcasting
let downcastedS = s as! Square
downcastedS.name
downcastedS.width
downcastedS.height
let downcastedS = s as! Rectangle
downcastedS.name
downcastedS.width
downcastedS.height
class Rhombus : Square {
var angle = 45.0
}
let dr = s as! Rhombus // Error
Type Casting
Type Check Operator
타입 체크는 런타임에서 실행됨
두 피연자의 형식이 동일하고, 동일한 상속 계층에 오른쪽이 Superclass라면 true 리턴
expression is Type
class Figure {
let name : String
init(name : String) {
}
func draw() {
print("draw \(name)")
}
}
class Rectangle : Figure {
var width = 0.0
var hegight = 0.0
override func draw() {
super.draw()
print("\(width) x \(height)")
}
}
class Square : Rectangle {
}
class Circle : Figure {
var radius = 0.0
override func draw() {
super.draw()
print("hi")
}
}
let t = Triangle(name : "Triangle")
let r = Rectangle(name : "Rect")
let s = Square(name : "Square")
let c = Circle(name : "Circle")
r is Rectangle // true
r is Figure // true
r is Square // false
Type Casting Operator
downcasing은 불안정하기 때문에 compile time cast는 사용할수 없음
downcasing은 불안정하기 때문에 옵셔널 바인딩과 함께 써주는 것이 좋음
expression as Type // Compile Time Cast
expression as? Type // Runtime Cast / Conditional Cast
expression as! Type // Runtime Cast / Forced Cast
Upcasting 된 인스턴스에서 메소드를 호출하더라도 실제 형식에서 overriding 한 메소드가 호출됨
class Figure {
let name : String
init(name : String) {
}
func draw() {
print("draw \(name)")
}
}
class Rectangle : Figure {
var width = 0.0
var hegight = 0.0
override func draw() {
super.draw()
print("\(width) x \(height)")
}
}
class Square : Rectangle {
}
class Circle : Figure {
var radius = 0.0
override func draw() {
super.draw()
print("hi")
}
}
let t = Triangle(name : "Triangle")
let r = Rectangle(name : "Rect")
let s = Square(name : "Square")
let c = Circle(name : "Circle")
let nsstr = "str" as NSString
// "str" as Int
var upcasted : Figure = s
upcasted = s as Figure
upcasted as? Square
upcasted as! Square
upcasted as? Rectangle
upcasted as! Rectangle
upcasted as? Circle // nil
upcasted as! Circle // Error
if let c = upcasted as? Circle {
}
let list = [t, r, s, c]
for item in list {
item.draw()
if let c = item as? Circle {
c.radius
}
}
Any, AnyObject
Any는 형식에 관계없이 모든 데이터 저장, 참조, 값형식 모두 가능
AnyObject는 참조형식만 저장 가능
Any, AnyObject는 형식에 대한 정보가 없음, 인스턴스를 사용하기 위해서는 타입캐스팅이 필요함
var data : Any = 1
data = 2.3
data = "str"
data = [1, 2, 3]
data = NSString()
var obj : AnyObject = NSString()
obj = 1 // Error
if let str = data as? String {
print(str.count)
} else if let list = data as? [Int] {
}
Type Casting Pattern
as연산자와 is 연산자를 사용, 범용 형식으로 저장되었거나 Upcasting된 인스턴스를 저장할 때 주로 사용
switch data {
case let str as String:
print(str.count)
case let list as [Int]:
print(list.count)
case is Double:
print("Double Value")
default:
break
}
Overloading
하나의 형식에서 동일한 이름을 가진 다수의 맴버를 구현할 때 사용
Overloading을 지원하지 않는 언어는 이름으로만 다름을 구별
1. 함수 이름이 동일하면 파라미터 수로 식별
2. 함수 이름, 파라미터 수가 동일하면 파라미터 자료형으로 식별
3. 함수 이름, 파라미터가 동일하면 Argument Label로 식별
4. 함수 이름, 파라미터, Argument Label이 동일하면 리턴형으로 식별
func process(value : Int) {
print("process Int")
}
func process(value : String) {
print("process String")
}
func process (value : String, anotherValue : String) {
}
func process(_ value : String) {
}
func process(value : Double) -> Int {
return Int(value)
}
func process(value : Double) -> String? {
return String(value)
}
let result : Int = process(value : 12.34)
let result = process(value : 12.34) as Int
struct Rectangle {
func area() -> Double {
return 0.0
}
static func area() -> Double {
return 0.0
}
}
let r = Rectangle()
r.area()
Rectangle.area()
'스피드 문법정리' 카테고리의 다른 글
20. Protocol (0) | 2020.06.23 |
---|---|
18. Initializer and Deinitializer (0) | 2020.06.22 |
16. Method and Subscript (0) | 2020.06.19 |
15. Property (0) | 2020.06.18 |
14. Structure and Class (0) | 2020.06.18 |