16. Inheritance and Polymorphism

Kang.__.Mingu·2021년 7월 26일
0

1. Study Swift

목록 보기
16/25

Inheritance and Polymorphism

상속을 통해 코드 중복을 줄이는 방법과 OOP의 특징 중 하나인 다형성에 대해 공부

Inheritance

클래스에서 상속을 통해 Super Class로부터 멤버를 상속하는 방법에 대해 공부

class ClassName: SuperClassName {...}
class Figure {
    var name = "Unknown"
    
    init(name: String){
        self.name = name
    }
    
    func draw() {
        print("draw \(name)")
    }
}

class Circle: Figure {
    var radius = 0.0
}

let c = Circle(name: "Circle")
c.radius
c.name
c.draw()

final class

final class ClassName: SuperClassName {...}
// final class는 상속이 금지된 클래스
final class Rectangle: Figure {
    var width = 0.0
    var height = 0.0
    
}

// 위에 final 클래스로 선언 되었기 때문에 상속을 받을 수 없다.
class Square: Rectangle {
    
}

Overrriding

Super Class로부터 상속한 멤버를 재정의하는 방법에 대해 공부

Overriding = 재정의
메서드, 속성, Subscripts, initializers(생성자)

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 선언해야됨
//    override func draw() {
//        super.draw()        // 부모 클래스 draw() 호출
//        print("🥊")
//    }
//}
//
//let c = Circle(name: "Circle")
//c.draw()

class Oval: Circle {
//    override var diameter: Double {
//        willSet {
//            print(newValue)
//        }
//        didSet {
//            print(oldValue)
//        }
    
//    ------
//        get {
//            return super.diameter
//        }
//        set {
//            super.radius = newValue/2
//        }
//    }
    
    // 속성은 메서드와 오버라이딩 하는 방법이 다르다.
    // 속성은 읽기 쓰기가 반드시 가능해야됨
//    override var radius: Double = 12.34
//    override var radius: Double {
//        willSet {
//            print(newValue)
//        }
//        didSet {
//            print(oldValue)
//        }
//    }
//}

let o = Oval(name: "Oval")
    o.radius
    o.draw()

Upcasting and Downcasting

인스턴스를 동일한 클래스 계층에 존재하는 다른 클래스 형식으로 처리하는 방법을 공부

class Figure {
    let name: String
    
    init(name: String) {
        self.name = name
    }
    
    func draw() {
        print("draw \(name)")
    }
}

class Rectangle: Figure {
    var width = 0.0
    var height = 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

// Upcasting
let s : Figure = Square(name: "Square")
//s.width
//s.height
//s.name

// as-타입 캐스팅
let downcastedS = s as! Rectangle
downcastedS.name
downcastedS.width
downcastedS.height

class Rhombus: Square {
    var angle = 45.0
}

// 상속 받는 것의 아래에 있으면 다운케스팅 오류
let dr = s as! Rhombus

Type Casting

Type Casting을 통해 인스턴스의 형식을 확인하고 다른 형식으로 캐스팅하는 방법을 공부

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("🔴")
   }
}

Type Check Operator

expression is Type
// 타입 연산자
// 타입 체크는 런타임에 실행
let num = 123

num is Int
num is Double
num is String

let t = Triangle(name: "Triangle")
let r = Rectangle(name: "Rect")
let s = Square(name: "Square")
let c = Circle(name: "Circle")

r is Rectangle
r is Figure
r is Square
r is Circle

Type Casting Operator

Compile Time Cast

expression as Type

Runtime Cast

expression as? Type		// Conditional Cast
expression as! Type 	// Forced Cast
// as 연산자

let nsstr = "Str" as NSString

//"str" as Int - 컴파일 에러

t as? Triangle
t as! Triangle

var upcasted: Figure = s
upcasted = s as Figure

upcasted as? Square
upcasted as! Square
upcasted as? Rectangle
upcasted as! Rectangle

upcasted as? Circle
//upcasted as! Circle

// 같이 사용
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
    }
}

// upcasting 되어 있는 인스턴스를 통해서 메서드를 호출하더라도 실제 형식에서 오버라이딩한 메서드가 호출된다.

Any and AnyObject

Swift가 제공하는 범용 자료형에 대해 공부

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

if let str = data as? String {
    print(str.count)
} else if let list = data as? [Int] {
    
}

Type Casting Pattern

// 업캐스팅 할 때 자주 사용
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

오버로딩을 통해 동일한 이름을 가진 멤버를 구현하는 방법에 대해 공부

이름은 같아도 파라미터 형식이 다르면 됨
규칙
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) {
    
}

process(value: 0)
process(value: "str")

process(value: "str")
process("str")

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()
profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글