Overriding vs Overloading

유재경·2022년 8월 2일
0

기타 스터디

목록 보기
1/1

이미지 순서대로 시작해보자!

오버로딩 Overloading

정의

  • 클래스 내의 메소드를 매개변수 혹은 리턴 타입 등을 다르게 하여 중복 선언이 가능(즉, 함수를 식별할 때에는 메소드명 뿐만 아니라 매개변수와 리턴타입까지 종합해서 식별)

코드

func sum(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func sum(_ a: Double, _ b: Double) -> Double {
    return a + b
}

func sum(_ a: String, _ b: String) -> String {
    return a + b
}

sum(1,3) // 4
sum(1.0,3.0) // 4.0
sum("a","b") // ab

오버라이딩 Overriding

정의

  • 상위 클래스로부터 상속받은 메소드, 프로퍼티를 "재정의"하는 것
  • 이미지에서 비유한 바와 같이 상위 클래스와 동일한 메소드명을 따로 선언하는 것이 불가(중복 선언 불가, 상속받는 메소드가 이어지도록..)

특징1. 메소드 오버라이딩

class Animal {
    func description() {
        print("동물입니다")
    }
}

class Cat: Animal {
    override func description() {
        super.description() // "동물입니다"
        print("고양이입니다") // "고양이입니다"
    }
    
    func description() { // !CompileError: 메소드명 중복
        print("고양이입니다")
    }
    
    override func printHello() { // !CompileError: 상위클래스에 해당 메소드가 없음
        print("고양이입니다")
    }
}

let cat = Cat.init()
cat.description()

특징2. 프로퍼티 오버라이딩

상속받은 프로퍼티를 오버라이딩하여 해당 속성에 대한 getter/setter를 제공하거나 상속받은 프로퍼티 값의 변경을 추적할 수 있도록 프로퍼티 옵저버 추가할 수 있다.

연산 속성 추가

서브 클래스에서는 상속된 프로퍼티의 특성이 저장 프로퍼티인지, 연산 프로퍼티인지 알 수 없고, 상속받은 프로퍼티의 이름과 타입 정도만 알고 있다.

따라서, 오버라이딩을 할 경우 프로퍼티의 이름과 타입을 반드시 명시해줘야 한다.

  1. 저장 프로퍼티
  • 서브클래스에서 상속받은 저장 프로퍼티에 초기화할 수 있는가? 안된다.
  • 서브클래스에서 상속받은 저장 프로퍼티에 '연산' 속성인 get, set을 추가 할 수 있는가? 안된다
  • 서브클래스에서 상속받은 저장 프로퍼티를 오버라이딩을 하고 싶다면? getter/setter구현이 필요
class Product {
    var name = "Pencil"
}

class Pencil: Product {

    // !Compile Error
   override var name: String = "Pencil2" // Cannot override with a stored property 'name'
    
    // !Compile Error
    var subName = "Pencil2"
    override var name: String {
        return self.subName // Cannot override mutable property with read-only property 'name'
    }
    
    // getter/setter로 오버라이딩 가능
    override var name: String {
        get {
            return self.subName
        }
        set {
            self.subName = newValue
        }
    }
}

let product: Product = .init()
product.name // Pencil
let pencil: Pencil = .init()
pencil.name // Pencil2
  1. 연산 프로퍼티
  • 저장 프로퍼티와 마찬가지로, 상위 클래스에서 getter/setter가 이미 구현되어있는데 오버라이딩하여 getter만 구현하는 것은 불가
  • 반대로 상위 크랠스에서 getter로만 구현되어있는 경우, 오버라이딩하여 getter만 구현 혹은 setter를 추가 가능
// 상위 클래스가 getter로만 구현된 경우
class Human {
    var name = "Jaekyung"
    
    var alias: String {
        return self.name + " 개발자"
    }
}

// 하위 클래스에서 getter만 구현
class Developer: Human {
    override var alias: String {
        return self.name + " iOS 개발자"
    }
}

// 하위 클래스에서 setter 추가 구현하여 getter/setter가진 경우
class Developer: Human {
    override var alias: String {
        get {
            return self.name + " iOS 개발자"
        } set {
            self.name = newValue
        }
    }
}

let human: Human = .init()
human.alias // "Jaekyung 개발자"

let developer: Developer = .init()
developer.alias // "Jaekyung iOS 개발자"

프로퍼티 옵저버 추가

  1. 저장 프로퍼티
  • var로 선언된 프로퍼티만 오버라이딩으로 옵저버 추가 가능
  • 옵저버는 값이 변경된 것을 알려주는 것인데 상수(let)면 값이 바뀔 일이 없기 때문
class Human {
    var name = "Jaekyung"
}

class Developer: Human {
    override var name: String {
        willSet {
            print("변경예정 \(newValue)") // "변경예정 iOS 개발자\n"
        }
        didSet {
            print("변경됨 \(oldValue)") //"변경됨 Jaekyung\n"
        }
    }
}
let developer: Developer = .init()
developer.name = "iOS 개발자"
  1. 연산 프로퍼티
  • getter/setter가 모두 구현된 경우만 오버라이딩으로 옵저버 추가 가능
  • getter만 구현된 경우, setter를 호출할 일이 없기 때문에 옵저버를 붙일 수가 없음
class Human {
    var name = "Jaekyung"
    
    var alias: String {
        get {
            return name + "사람"
        }
        set {
            self.name = newValue
        }
    }
}

class Developer: Human {
    override var name: String {
        willSet {
            print("상속받은 name을 \(newValue)로 변경 예정") // "상속받은 name을 iOS 개발자로 변경 예정\n"
        }
        didSet {
            print("상속받은 name은 원래 \(oldValue)였음") // "상속받은 name은 원래 Jaekyung였음\n"
        }
    }
}

let developer: Developer = .init()
developer.name = "iOS 개발자"

특징3. final = 오버라이딩 불가

  • class앞에 'final'키워드를 붙이면(final class) 해당 클래스의 상속을 금지하는 것과 마찬가지로 프로퍼티, 메소드, 서브스크립트 앞에 'final'키워드를 붙이면 오버라이딩 불가
class Human {
    final var name = "Jaekyung"
    final func description() {
        print("안녕하세요!")
    }
}

class Developer: Human {
    // !Compile Error
    override func description() {
        // Instance method overrides a 'final' instance method
    }
}

정리


무언가를 구분하고 익힐 때에는 이미지와 코드 예제가 참 기억에 많이 남게 되는것 같다!

참고:
오버로딩 https://babbab2.tistory.com/129
오버라이딩 https://babbab2.tistory.com/126
https://programmingnote.tistory.com/29

profile
iOS 개발

0개의 댓글