swift

swift - Inheritance and Polymorphism #1 (Inheritance, Final Class, override, Upcasting, Downcasting)

행복하게사는게꿈 2021. 1. 12. 12:34

Inheritance

네 군데 모두 동일한 속성을 선언하면 매우 불합리한 코딩

 

공유되는 속성을 하나 선언하고 네개의 클래스가 하나의 속성을 상속받아서 사용

 

swift는 다중상속을 지원하지 않고 protocal을 사용해서 해결

 


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

class Cirlce: Figure {
    var radius = 0.0
    var diameter: Double {
        return radius
    }
    override func draw() {
        super.draw()
        print("radius \(radius)")
    }
}


let c = Cirlce(name: "jaeho") // 상속받은 init사용
c.radius
c.name // 상속받은 속성 사용
c.draw() // 상속받은 메소드 override해서 사용


// 속성 override 하는 방법
// 1. computed property 방식
class Oval: Cirlce {
    
    override var radius: Double {
        // 읽기, 쓰기 모두 되는 속성인 경우
        get {
            return super.radius
        }
        set {
            super.radius = newValue
        }
    }
    
    override var diameter: Double {
        get {
            return super.diameter
        }
        set {
            super.radius = newValue / 2
            // 읽기전용 속성에는 값을 set할수 없고 다른 속성에 set하게 만들 수 있음
            // super.diameter = 11
        }
    }
}

// 2. property observer 방식
class Oval2: Cirlce {
    override var radius: Double {
        willSet {
            print(newValue)
        }
        didSet {
            print(oldValue)
        }
    }
    
    // read-only속성은 값을 감시할 수가 없다 -> 즉 읽기전용에서는 property observer방식 불가능
//    override var diameter: Double {
//        willSet {
//            print(newValue)
//        }
//        didSet {
//            print(oldValue)
//        }
//    }
}

// 클래스를 상속 하게 할 수 있고 특정 메소드를 override 금지시키기
// 금지하고 싶은 변수, 메소드에 final 키워드 추가

 

final class Rectangle: Figure {
    var width = 0.0
    var height = 0.0
}

// final class는 상속이 금지된 클래스임
class Square: Rectangle {
    
}

Upcasting

 서브 클래스 인스턴스를 슈퍼 클래스 형식으로 저장

 

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.height
s.name
s.width
s.draw()

이 상태에서는 밑에 그림처럼 width, height도 메모리 공간에 생성되긴 하지만 Figure클래스의 name에만 접근 할 수 있는 형태이다.


Downcasting

// Downcasting
// Upcasting된 인스턴스를 원래 형식으로 처리하기 위해 필요
// 항상 성공하는게 아님
let downcastedS = s as! Square
downcastedS.name
downcastedS.width
downcastedS.height



class Rhombus: Square {
    var angle = 45.0
}

let dr = s as! Rhombus

s라는 Figure 클래스에는 name, width, height가 있는데 Rhombus로 downcasting하려면 err가 발생한다.

 

왜? Rhombus에 선언된 angle이라는 변수는 Figure 클래스에 존재하지 않기 때문에