class Figure {
let name: String
init(name: String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
class Triangle: Figure {
override func draw() {
super.draw()
print("🔺")
}
}
class Rectangle: Figure {
var width = 0.0
var height = 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("🔴")
}
}
// 두 피연산자의 타입이 일치하면 true
// 왼쪽 피연산자의 형식이 오른쪽 피연산자의 형식과 동일한 상속계층에 있고 오른쪽 피연산자의 형식이 슈퍼 클래스이면 true
// 나머지는 false
// type check는 run time에 실시된다.
let num = 123
num is Int // true
num is Double // false
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
// 왼쪽에 표현식 오른쪽에 형식
// 왼쪽 피연산자의 형식이 오른족 형식과 호환된다면 오른쪽 형식으로 casting된 인스턴스를 return -> 새로운 인스턴스가 리턴되는게 아님
// 이미 존재하는 인스턴스에서 오른쪽 피연산자의 형식의 멤버만 접근할 수 있는 임시 인스턴스를 리턴
// 형식 3개가지
// 1. compile time casting (bridging : 서로 호환되는 형식을 casting하는 것)
// 예시
// 구조체로 구현된 String 자료형은 클래스로 구현된 NSString 자료형과 호환된다.
let nsstr = "str" as NSString
// 캐스팅 실패시 compile err
// "str" as Int
// 2. runtime Cast
// 2-1. Conditional Cast
// ?가 붙어있는 경우
// casting에 성공하면 캐스팅된 인스턴스를 리턴하고 실패하면 nil리턴
t as? Triangle
t as! Triangle
// 2-2. forced casting
// 캐스팅에 실패하면 crush 발생
var upcasted: Figure = s
// compile time casting으로 upcasting
upcasted = s as Figure
upcasted as? Square
upcasted as! Square
upcasted as? Rectangle
upcasted as! Rectangle
upcasted as? Circle // nil
// upcasted as! Circle // crush
// 실제로 donwcasting을 구현할 때는
// conditional과 optional을 같이 사용하는게 좋다.
if let c = upcasted as? Circle {
}
// 배열에는 동일한 형식만 저장할 수 있는데 요기서 보면 에러없이 잘 생성됨
// 모든 요소가 동일한 상속계층에 있다면 가장 근접한 슈퍼 클래스로 upcasting되서 들어간다.
let list = [t, r, s , c]
for item in list {
// 현재 list안의 요소들은 Figure로 upcasting된 상태지만
// 실행시켜보면 각각 다른 draw 결과물이 실행된다.
// 이것을 polymorphism, 다형성이라고 한다.
item.draw()
// Figure에 선언된 멤버변수에만 접근할 수 있다.
// 그럼 radius속성에 접근하는 방법은? -> downcasting
// item.radius
if let c = item as? Circle {
print(c.radius)
}
}