Swift - Struct / Class (4_클래스의 상속과 타입캐스팅)

이한솔·2023년 8월 8일
0

Swift 문법 🍎

목록 보기
16/32

클래스의 상속

클래스가(subclass) 다른 클래스에서(superclass) 정의된 프로퍼티나 메서드를 물려받아 사용하는 것

// 부모 클래스
class Name {
    var name = "Lee"
    
    func myname() {
        print("my name is \(name)")
    }
}


// 자식 클래스
class YourName : Name {
    var yourName = "Park"
    
    func ourName() {
        print("my name is \(name) and your name is \(yourName)")
    }
}

let names = YourName()

// 클래스 상속으로 name 프로퍼티 사용 가능
print(names.name) // 출력값: Lee
print(names.yourName) // 출력값: Park

//클래스 상속으로 myname 메소드 사용 가능
names.myname() // 출력값: my name is Lee
names.ourName() // 출력값: my name is Lee and your name is Park


overriding

자식 클래스는 일반적으로 부모 클래스로부터 상속받은 프로퍼티나 메서드를 그대로 사용하지만, 필요에 의해 이를 다시 구현하거나 재정의하려면 부모클래스에서 상속 받은 내용을 오버라이딩해서 사용해야 한다. 메서드를 오버라이딩 할 때 매개변수의 개수, 타입, 반환 타입은 변경할 수 없다.

프로퍼티 오버라이딩 시 가능한 것과 불가능한 것

  1. 저장프로퍼티 -> get, set이 모두 있는 연산프로퍼티
    (저장프로퍼티, get만 있는 연산 프로퍼티 안됨)

  2. get 연산프로퍼티 -> get / get, set 연산프로퍼티

  3. get, set 연산프로퍼티 -> get, set 연산프로퍼티
    (get, set 연산프로퍼티 -> get만 있는 연산프로퍼티 안됨)

  4. 연산프로퍼티 -> 저장프로퍼티 안됨

💡 오버라이딩한 뒤에 이전에 프로퍼티나 메서드를 사용하고 싶을때는?
스위프트에서는 상속받은 부모 클래스의 인스턴스를 참조할 수 있도록 super라는 객체를 제공하는데, 이 객체를 이용하면 부모 클래스의 프로퍼티나 메서드를 호출할 수 있다.

// 부모 클래스
class Vehicle {
    var currentSpeed = 0.0
    
    var description: String {
        return "시간당 \(self.currentSpeed)의 속도로 이동하고 있습니다"
    }
    
    func makeNoise() {
        print("부모 makeNoise")
    }
}


// 1. 자식 클래스
class Car: Vehicle {
    var gear = 0
    var engineLevel = 0
    
    // 저장프로퍼티 -> get, set이 모두 있는 연산프로퍼티
    override var currentSpeed: Double {
        get {
            return Double(self.engineLevel * 50)
        }
        set {
            // 아무것도 하지 않음
        }
    }
    
    // 저장프로퍼티 -> get, set이 모두 있는 연산프로퍼티
    override var description: String {
        get {
            return "Car: engineLevel = \(self.engineLevel), so currentSpeed = \(self.currentSpeed)"
        }
        set {
            print("New Value is \(newValue)")
        }
    }
}


let c = Car()

c.engineLevel = 5 // (c.currentSpeed = 250)
c.description = "New Class Car"

print(c.description)
// 출력값: New Value is New Class Car
// Car: engineLevel = 5, so currentSpeed = 250.0


// 2. 자식 클래스
class Bike: Vehicle {
    override func makeNoise() {
        print("빠라빠라빠라밤")
    }
    
   func originalMakeNoise(){
        super.makeNoise()
    }
   
}

let bk = Bike() 
bk.makeNoise() // 출력값: 빠라빠라빠라밤
bk.originalMakeNoise() // 출력값: 부모 makeNoise

💡 오버라이딩을 막고 싶을때는?

상위 클래스의 입장에서 하위 클래스가 자신의 기능을 재정의하는 것을 막아야 할 때 final 키워드를 프로퍼티나 메서드를 정의하는 var, func 등의 키워드 앞에 붙이면 된다.

class Vehicle {
    final var currentSpeed = 0.0
    
    final var description: String {
        return "시간당 \(self.currentSpeed)의 속도로 이동하고 있습니다"
    }
    
    final func makeNoise() {
     
    }
}
// 프로퍼티나 메서드 오버라이딩 금지시킴


final class Vehicle {

}
// 클래스 상속 자체를 금지, 인스턴스로만 사용 가능한 클래스가 됨


타입 캐스팅

타입비교연산

스위프트는 타입 비교 연산자 is로 변수나 상수 또는 인스턴스에 이 연산자를 사용해서 할당된 값을 비교하는 것이 아니라 타입 일치 여부를 비교해서 결과를 Bool값으로 return 한다.

import UIKit

// is : 타입 확인
let cell = UITableView()

if cell is UITableView {
    print("cell is a UITableView.")
} 
// 출력값 : cell is a UITableView.

Up Casting

as키워드로 해당 타입의 상위 타입의 인스턴스로 캐스팅한다.

Down Casting

as! : 강제 다운캐스팅, 확실한 상황에서만 사용해야한다.
as? : 선택적 다운캐스팅, 확실하지않아도 에러는 나지않지만 옵셔널 타입으로 다운캐스팅 된다.

class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    
    }
}

// Animal class를 상속받은 Human class
class Human: Animal {
    
    func sayHello(){
   
   }
}

// Animal class를 상속받은 Fish class
class Fish: Animal {
    
    func breatheUnderWater(){
        print("Breathing under water.")
    }
}

var hansol = Animal(name: "Hansol")
var sol = Human(name: "sol")
var nimo = Fish(name: "Nimo")

// 전부 Animal 클래스를 상속받아서 Animal타입으로 사용 가능
var neighbours: [Animal] = [hansol, sol, nimo]


func findNimo(from animals: [Animal]){
    for animal in animals{
        if animal is Fish {
            print(animal.name)
            
            let fish = animal as! Fish
            fish.breatheUnderWater()
            // animal.breatheUnderWater()로 쓸 수 없고 as!로 Fish타입으로 다운캐스팅 해야한다.
        }
    }
}

findNimo(from: neighbours) 
// 출력값: Nimo 
// Breathing under water.
         
         
if let fish = neighbours[1] as? Fish  {  // Human 타입의 sol
    fish.breatheUnderWater()
} else {
    print("다운캐스팅 실패")
}  
// 출력값: 다운캐스팅 실패

0개의 댓글