티스토리 뷰

INDEX

1.  상속(Inheritance)

2.  재정의(Overriding)

3. ⭐️속성의 재정의(Overriding Properties)⭐️

4. 메서드의 재정의(Overriding Methods)

5. final 키워드

6. 마무리

 

 

1.  상속(Inheritance)

상속: 쉽게 말하면, 본질적으로 성격이 비슷한 타입을 새로 만들어 

1) 데이터(저장속성)를 추가하거나 2) 기능(메서드)를 변형시켜 사용하는 것

Swift에서는 클래스만 상속기능을 보유하고 있으며 다중상속이 불가능하다. 

상속은 자식에게 특성을 물려주는 부모클래스(Superclass)와 이를 상속받는 자식클래스(SubClass)의 형태다.

상속을 받는 서브클래스는 슈퍼클래스의 모든 멤버(속성, 메서드)를 상속 받는다.

class AClass {
    var name = "이름"
}

// BClass는 AClass를 상속해서 구현
// 서브클래스는 슈퍼클래스로부터 멤버를 상속함
class BClass: AClass {
    // name
    var id = 0
}

// 클래스의 상속, 재정의 금지의 키워드 final(실제로 앱을 만들때 사용)

class Person {
    var id = 0
    var name = "이름"
    var email = "abc@gmail.com"
}

class Student: Person {
    // id
    // name
    // email
    var studentId = 0
}

class Undergraduate: Student {
    // id
    // name
    // email
    // studentId
    var major = "전공"
}

 

2. ⭐️재정의(overriding)⭐️

 

재정의(Overriding)란?

재정의란 상위 클래스에 존재하는 멤버를 변형시키는 것으로 상위클래스가 갖고 있던 속성, 메서드를 '재정의'하는 것을 뜻한다. 재정의에 관해서는 구조체와 클래스에서 한번 간단히 정리하였고, 재정의 방식에는 오버라이딩과 오버로딩이 있었다.

오버라이딩(overriding) : 상위 클래스가 가지고 있는 속성이나 메서드를 하위 클래스가 재정의(override)해서 사용

오버로딩(overloading) : 메서드의 파라미터(타입, 갯수, Argument Label), 리턴타입을 다르게 선언하여, 같은 이름의

함수여도 각기 다르게 사용

(둘의 차이를 더 알고 싶다면 https://purelime.tistory.com/entry/ㅈㄷ  

밑부분에 이해하기 쉬운 코드를 예시로 정리해 놓았다.)

이번 포스팅에서는 오버라이딩(overriding)에 대해 중점적으로 다룬다.

 

재정의에는 2가지 대원칙이 존재한다.

1. 저장 속성 재정의 불가

2.메서드는 자유롭게 재정의 가능(다만, 기능 확장만 가능하다. 기능 축소는 불가함)

(물론, 너무나 당연하지만, 상속시 재정의를 일일이 해주지 않아도 모든멤버의 상속은 일어난다.) 

class SomeSuperclass {
    // 저장속성
    var aValue = 0
    
    // 메서드
    func doSomething() {
        print("Do something")
    }
}

class SomeSubClass: SomeSuperclass{
    // 저장속성의 재정의는 원칙적 불가
    //override var aValue = 3 //불가능
    
    //저장속성 => 계산속성으로 재정의 가능(기능확장은 가능함. But read-only(get블록만)로는 구현불가)
    override var aValue: Int{
        get { return 1 }
        set { super.aValue = newValue} //self.aValue하면 오류
    }
    // 메서드는 (어떤 형태로든)재정의 가능
    override func doSomething() {
        //super.doSomething()
        print("Do nothing!!!")
    }
}

 

3. ⭐️속성의 재정의(Overriding Properties)⭐️

 

메서드와 달리 속성의 재정의는 매우매우 엄격하기에 먼저 다룬다.  각 속성별로 재정의가 가능한 범위도 달라 처음 보면 헷갈릴 수도 있으므로 이를 나누어 정리할 필요가 있다고 보았다.

(Tip은 속성을 재정의할때는 확장만 허용하는구나라고 생각하고 접근하면 편하다. 단순 메서드 추가의 관점으로 바라보자

 

3-1. 저장속성 재정의(Only 기능 확장만 가능)

앞서 강조했듯 저장속성은 원칙적으로 재정의가 불가하다. ex)override var aValue = 3 불가능

하지만 계산속성으로 재정의하는 것은 가능하고 (단 기능 확장만가능하기에 get블록(읽기)과 set블록(쓰기)을 함께 구현)

속성감시자로 재정의도 가능하다.(실질적 단순 메서드의 추가)

class Vehicle {
    var currentSpeed = 0.0

    var halfSpeed: Double {
        get {
            return currentSpeed / 2
        }
        set {
            currentSpeed = newValue * 2
        }
    }
}

//저장속성 -> 계산속성 재정의
class MyBicycle1:Vehicle {
    override var currentSpeed: Double{
        get{ return super.currentSpeed } //super키워드!
        set{ super.currentSpeed = newValue }
    }
}

//저장속성 -> 속성감시자 재정의
class MyBicycle2: Vehicle{
    override var currentSpeed: Double{
        willSet { print("값이 \(currentSpeed)에서 \(newValue)로 바뀔 예정입니다.") }
        didSet { print("값이 \(oldValue)에서 \(currentSpeed)로 바뀔 예정입니다.") }
    }
}

 

3-2. 계산속성 재정의(기능유지 + 확장)

계산속성은 저장속성처럼 기능확장이 가능하고 기능유지도 가능하다.(실질적 단순 메서드의 추가의 관점)

기능축소는 절대 불가능.

읽기 메서드(get-only) -> 읽기 + 쓰기 메서드(O)

읽기 메서드(get-only) -> 읽기 메서드(get-only)(O)

읽기 + 쓰기 메서드 -> 읽기 + 쓰기 메서드(O)

읽기 + 쓰기 -> 읽기 (X)

class Vehicle {
    var currentSpeed = 0.0

    var halfSpeed: Double {
        get {
            return currentSpeed
        }
    }
}

class MyBicycle3:Vehicle{
    override var halfSpeed: Double{
        get { return currentSpeed / 2}
        set {currentSpeed = newValue * 2}
    }
}

let my = MyBicycle3()
my.halfSpeed = 20
my.halfSpeed //20
my.currentSpeed //40

계산속성 -> 속성감시자도 가능하다.

(물론 부모클래스의 계산속성에 set블록이 구현되어 있어야 한다. get블록만 있다면, 값 변경이 불가하다.)

why 저장속성 -> 속성 감시자는 가능했을까?

저장속성의 특성상 언제든 값변경이 쉽게 가능한 getter와 setter기능이 내장된 '저장'속성이기 때문.

class Vehicle {
    var currentSpeed = 0.0

    var halfSpeed: Double {
        get {
            return currentSpeed / 2
        }
        set {
            currentSpeed = newValue * 2
        }
    }
}
class Bicycle4: Vehicle {
    override var halfSpeed: Double {
        willSet {
            print("값이 \(halfSpeed)에서 \(newValue)로 변경 예정")
        }
        didSet {
            print("값이 \(oldValue)에서 \(halfSpeed)로 변경 예정")
        }
    }
}

 

3-3. 타입속성 재정의

타입속성은 static 키워드 사용시 모든 재정의가 불가하다

class 키워드로 재정의시 계산속성만 재정의(확장방식)가 가능하다.

class Vehicle {
    class var currentSpeed: Double{
        get { return 0.0 }
    }
}

class Bicycle5: Vehicle{
    override class var currentSpeed: Double{
        get{ return 2.0 }
    }
}

 

3-4. 속성 감시자 재정의

속성 감시자 추가는 단순메서드의 추가 형태이기에 가능하다. 위의 다른 속성들의 코드에서 보여주었기에 생략한다.

 

4. 메서드의 재정의(Overriding Methods)

메서드(메서드, 서브스크립트, 생성자)의 재정의는 속성에 비해 자유롭다. 생성자가 다소 까다롭고 다룰게 많기 때문에 (다음 포스팅에서 집중해서 다루기로 하고) 일반적인 함수와 서브스크립트 형태만 코드로 예시를 들었다.

 

class Vehicle1 {
    var currentSpeed = 0.0
    var datas = ["1", "2", "3", "4", "5"]
    func makeNoise() {
        print("경적을 울린다.")
    }
    
    subscript(index: Int) -> String {
        get {
            if index > 4 {
                return "0"
            }
            return datas[index]
        }
        set {
            datas[index] = newValue
        }
    }
}


// 메서드의 재정의 방식 ⭐️

class Bicycle1: Vehicle1 {
    
    // 1) 상위 => 하위 호출 (가능)
//    override func makeNoise() {
//        super.makeNoise()
//        print("자전거가 지나간다고 소리친다.")
//    }
    
    // 2) 하위 => 상위 호출 (가능)
//    override func makeNoise() {
//        print("자전거가 지나간다고 소리친다.")
//        super.makeNoise()
//    }
    
    // 3) 상위구현 아예 무시 (가능)
    override func makeNoise() {
        print("경적을 울리고, 자전거가 지나간다고 소리친다.")
    }
    
    // 서브스크립트도 재정의 가능
    override subscript(index: Int) -> String {
        get {
            if index > 4 {
                return "777"
            }
            return super[index]
        }
        set {
            super[index] = newValue
        }
    }
}


let v = Bicycle1()
v.currentSpeed
v.makeNoise()
v[0] //1

 

5. final 키워드

오버라이딩 금지 키워드 final

추가적인 재정의를 방지하고자 할때 사용하는 키워드로 실수로 메서드, 프로퍼티, 또는 서브 스크립트를 재정의 하는 것을 방지할 수 있다. final키워드가 있는 class는 더 이상 자식클래스를 가질 수 없으며 이를 상속받으려 한다면 컴파일에러 발생❗️

 

  •  

아래는 공식문서의 상속 단원에 있는 코드들을 모두 모아 놓은 것이다. 맨밑의 AutomaticCar 클래스에는 final키워드가 표시되어 있다. 한번 쭉 보면서 정리를 해도 좋을 것 같다.

//기본 상위클래스
class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // do nothing - an arbitrary vehicle doesn't necessarily make a noise
    }
}


let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour

//하위클래스
class Bicycle: Vehicle {
    var hasBasket = false
}


let bicycle = Bicycle()
bicycle.hasBasket = true


bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}


let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour


//메서드 재정의
class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}


let train = Train()
train.makeNoise()
// Prints "Choo Choo"

//프로퍼티 재정의
class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}


let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3

//난 마지막 subclass!!!
final class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}


let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4

6. 마무리

이번 단원은 그렇게 어려운 단원은 아니다. 상속이 어떤건지, override를 어떻게 각 멤버에 재정의하면 되는지를 알았다면 된다. 위의 항목별 예시코드들과 마지막 공식문서의 예제가 읽히는 정도면 충분할 것 같다. 다음 포스팅은 생성자인데 여기가 처음 공부할때 버거웠다. SWIFT는 언어의 본 목적이 앱개발인 만큼, 목적에 충실하게 함수형 프로그래밍, 객체지향, 프로토콜 지향등 다른언어의 특화된 점들을 취합했다는 점에서 배우는 데 재미있고 매력적인 언어는 맞지만, 생각보다 까다롭고 엄격히 지켜야할 사항들이 존재했다. 특히 생성자 단원이 그러했다. 시간이 지나고 까먹을 수도 있겠지만 처음 다지는 것인 만큼 제대로 정리해 놓기 위해서 옵셔널이후로 2번째로 힘주어 꼼꼼하게 다뤄보고자 한다.

 

출처

Inflearn Allen님의 강의 노트

Swift 공식문서

야곰님의 스위프트 프로그래밍 3

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함