새벽의 기록

[SOPT] 문법 스터디 #5 상속 본문

SOPT/문법 스터디

[SOPT] 문법 스터디 #5 상속

OneTen 2024. 11. 15. 00:51
1. 상속
    - Overriding 키워드에 대해 알아보고, 제한사항에 대해 알아봅시다
    - super 키워드
    - final 키워드
    - 프로토콜과 상속은 얼핏 비슷하게 느껴질 수 있는 서로 다른 개념입니다. 
      둘의 특징을 간단히 정리하고, 차이를 알아봅시다 !! (Protocol vs Inheritance)

 

상속

1. Overriding 키워드에 대해 알아보고, 제한사항에 대해 알아봅시다

애플공식문서
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/inheritance/

Documentation

docs.swift.org

 
 

💡"하위 클래스는 슈퍼클래스로부터 상속되는 인스턴스 메서드, 유형 메서드, 인스턴스 속성, 유형 속성 또는 구독자의 고유한 사용자 지정 구현을 제공할 수 있습니다. 이것을 오버라이딩이라고 합니다."

 
override는 상속받은 클래스의 메서드나 프로퍼티 등을 재정의할 때 사용되는 키워드.
이 키워드를 통해 상위 클래스에서 정의된 기능을 하위 클래스에서 덮어씌우거나 확장할 수 있다.
Swift에서는 상위 클래스의 메서드를 오버라이드할 때 반드시 override 키워드를 명시해야 한다.
→ 이를 통해 의도치 않은 오버라이드를 방지하고 코드의 가독성을 높이는 데 도움을 준다.

override의 사용 목적

  1. 상위 클래스의 기능 확장
  2.  상위 클래스의 기본 동작을 하위 클래스에서 변경해, 특정 상황에 맞게 동작을 변경할 수 있다.
  3. 특정 기능 추가
  4.  상위 클래스의 동작을 그대로 수행하면서 하위 클래스만의 기능을 추가할 수 있다.
  5. 메서드, 프로퍼티의 다형성
  6.  다형성을 지원하여 동일한 이름의 메서드를 호출해도 클래스의 타입에 따라 다른 동작을 수행할 수 있다.

override 사용 예시

class Animal {
    func sound() {
        print("대충 동물 울음소리")
    }
}

class Cat: Animal {
    func sound() {
        print("야옹")
    }
}

// Error: Overriding declaration requires an 'override' keyword

Animal을 상속받은 Cat에서 sound 메서드를 쓰려고 하면 "override"란 키워드를 써야 한다며 에러가 남
→ 이미 상속받는 클래스인 Human 클래스에 동일한 메서드가 있기 때문
→ 오버라이딩 하고 싶은 메서드 앞에 override란 키워드 붙여주기

메서드 오버라이딩

상위 클래스의 메서드를 하위 클래스에서 재정의

class Animal {
    func sound() {
        print("대충 동물 울음소리")
    }
}

class Cat: Animal {
    override func sound() {
        print("야옹")
    }
}

let animal: Animal = Dog()
animal.sound() // 야옹

Cat 클래스는 Animal 클래스의 sound() 메서드를 override해서 고양이 울음소리를 출력하도록 변경.

프로퍼티 오버라이딩

상속받은 프로퍼티를 오버라이딩하여 해당 속성에 대한 getter, setter를 제공하거나 상속받은 프로퍼티 값의 변경을 추적할 수 있도록 프로퍼티 옵저버를 추가할 수 있다.
→ 연산 속성을 추가할 수 있고, 프로퍼티 옵저버를 추가할 수 있음
 
하위 클래스에서는 상속된 프로퍼티의 특성이 저장 프로퍼티인지, 연산프로퍼티인지 알 수 없으며 상속받은 프로퍼티의 이름과 타입 정도만 알고 있다.
→ 따라서 오버라이딩할 경우 프로퍼티의 이름과 타입을 반드시 명시해야한다.
 
 
저장 프로퍼티에 "저장" 속성을 추가하는 오버라이딩은 안 될까?

class Human {
    var name = "Kim"
}
 
class Teacher: Human {
    override var name: String = "Kim2"       
}

// Error: Cannot override with a stored property 'name'

안됨. 저장 프로퍼티 name을 오버라이딩 할 수 없다는 에러 발생
→ 연산 속성만 추가가능
 
 
상위 클래스의 프로퍼티를 하위 클래스에서 연산

class Human {
    var name = "Kim"
    
    var fullName: String {
        return self.name
    }
}
 
class Teacher: Human {
    override var fullName: String {
        return self.name + "Hanyeol"
    }
}

let human = Human()
print(human.fullName)

let teacher = Teacher()
print(teacher.fullName)

// Kim
// KimHanyeol

 
 
 
속성 감시자(Property Observer) 도 오버라이딩 할 수 있음.
willSet 은 값이 변경되기 직전에 호출, didSet 은 값이 변경된 직후 호출

import Foundation

class Person {
    var name: String = "Anonymous" {
        willSet {
            print("실행되기 직전 이름1: \\(name)")
        }
        didSet {
            print("실행 직후 이름1: \\(name)")
        }
    }
}

class Person2: Person {
    override var name: String {
        willSet {
            print("실행되기 직전 이름2: \\(name)")
        }
        didSet {
            print("실행 직후 이름2: \\(name)")
        }
    }
}

let Park = Person2()
Park.name = "Park"

// 실행되기 직전 이름2: Anonymous
// 실행되기 직전 이름1: Anonymous
// 실행 직후 이름1: Park
// 실행 직후 이름2: Park

 

2. super 키워드

오버라이드된 메서드나 프로퍼티에서 super 키워드를 사용하면 상위 클래스의 원래 메서드나 프로퍼티도 호출할 수 있다.

class Animal {
    func move() {
        print("동물은 꿈틀꿈틀")
    }
}

class Fish: Animal {
    override func move() {
        super.move() // 상위 클래스 메서드 호출
        print("물.. 물코기")
    }
}

let fish = Fish()
fish.move()

// 동물은 꿈틀꿈틀
// 물.. 물코기

3. final 키워드

final 키워드를 사용하면 특정 메서드, 프로퍼티, 서브스크립트가 하위 클래스에서 오버라이드되는 것을 막을 수 있고,
클래스 자체에도 적용해서 상속이 불가능하게 할 수 있다.

class Animal {
    final func eat() {
        print("냠냠")
    }
}

class Dog: Animal {
    override func eat() {
        print("쩝쩝")
     } 
}
// 에러: 'eat' 메서드는 final이기 때문에 오버라이드할 수 없음

 

4. 프로토콜과 상속은 얼핏 비슷하게 느껴질 수 있는 서로 다른 개념입니다. 둘의 특징을 간단히 정리하고, 차이를 알아봅시다 !! (Protocol vs Inheritance)

 
Swift에서 상속과 프로토콜은 객체 간의 관계와 코드 재사용성을 높이기 위해 사용하는 두 가지 주요 개념이다.
 

상속 (Inheritance)

• 클래스에만 적용가능하며 구조체나 열거형에서는 사용할 수 없음.
• 단일 상속을 지원하므로, 클래스는 오직 하나의 부모 클래스만 가질 수 있다.
• 상속받은 속성과 메서드를 자식 클래스에서 물려받고 확장할 수 있다.
• Overriding을 통해 부모 클래스의 메서드나 프로퍼티를 재정의하여 자식 클래스에서 고유의 기능으로 수정할 수 있다.

class Animal {
    func move() {
        print("동물은 꿈틀꿈틀")
    }
}

class Fish: Animal {
    override func move() {
        super.move() // 상위 클래스 메서드 호출
        print("물.. 물코기")
    }
}

let fish = Fish()
fish.move()

// 동물은 꿈틀꿈틀
// 물.. 물코기

 

 

프로토콜 (Protocol)

• 클래스, 구조체, 열거형에 적용할 수 있는 규약.
• 다중 채택이 가능하여, 한 타입이 여러 프로토콜을 동시에 구현할 수 있다.
• 프로토콜은 요구 사항만을 정의하며, 실제 구현은 이를 채택한 타입에서 수행. → 자바에서의 추상클래스 느낌
• 프로토콜 익스텐션을 통해 프로토콜의 기본 구현을 추가할 수 있어 코드 재사용성을 높일 수 있습니다.

protocol Move {
    func move()
}

class Fish: Animal {
    func move() { 
        print("물.. 물코기")
    }
}

let fish = Fish()
fish.move()

// 물.. 물코기

정리하자면,
상속은 클래스 간의 관계에서 사용되며, 특정 기능을 자식 클래스에 물려주고 싶을 때 적합.
프로토콜은 여러 타입에 공통 행동을 강제하고 싶을 때 사용. 다중 채택이 가능하고 클래스, 구조체, 열거형 모두에 적용할 수 있음.

Comments