Swift/개념 & 응용

[Swift] Swift 문법 - 상속

유정주 2021. 8. 27. 00:10
반응형

안녕하세요.

 

오늘은 Swift 문법 중 상속에 대해 알아보겠습니다.

상속도 객체지향에서 핵심 개념 중 하나입니다.

사람이라는 객체를 상속해서 학생, 선생님 등의 객체로 확장되는 것처럼 

객체가 상속을 통해 확장되는다는 것이 핵심입니다.

또한 다른 사람이 만든 클래스를 가지고 와 자신의 클래스로 커스텀하여 사용할 수 있다는 것도 중요합니다.

 

그럼 시작하겠습니다. 


참고 자료

해당 포스팅은 Smile Han님의 유튜브 영상을 참고하며 작성하였습니다.

https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA


상속

상속은 객체지향의 큰 특징 중 하나입니다.

다른 사람의 클래스를 상속하여 자신이 원하는 기능을 추가, 수정할 수 있기 때문인데요.

상속된 클래스는 부모 클래스의 모든 기능을 상속받으며 자신만의 기능을 추가할 수 있습니다.

 

이렇게 상속받은 클래스(자신이 수정한 클래스)를 하위 클래스(subclass) 또는 자식 클래스(child class)라고 하고

상속한 클래스를 상위 클래스(superclass) 또는 부모 클래스(parent class)라고 합니다.

이번 포스팅에서는 부모 클래스, 자식 클래스로 언어를 통일하겠습니다.

 

Swift는 클래스만 상속이 가능합니다.

열거형(enum), 구조체도 문법은 클래스와 비슷하지만 상속은 불가능합니다.

 

Swift는 단일 상속(Single Inheritance)만을 허용합니다.

단 하나의 부모 클래스만을 가질 수 있다는 의미입니다.

 

상속을 하는 방법은 아래와 같습니다.

class 자식: 부모 {

}

실제 클래스가 정의된 것을 보면 콜론 옆에 하나만 있는 게 아니라 여러 가지가 들어가 있는데요.

언뜻 보면 단일 상속에 위반되는게 아닌가 생각이 들 수도 있습니다.

하지만 여러 가지 중 콜론 바로 옆에 오는 맨 첫 번째 클래스만 부모 클래스이고

나머지는 다음 포스팅에서 다룰 프로토콜이라는 것입니다.

 

Swift는 단일 상속만을 허용한다는 것만 기억하시면 됩니다.

 

클래스 상속 예시

class Person {
    var name = "Unknown"
    var age = 0
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    func printInfo() {
        print("\(name) is \(age)")
    }
}

class Student: Person { //Person을 부모클래스로 사용
    //비어 있지만 Person 클래스의 모든 것을 갖고 있다.
}
    
var jeong = Person(age: 22, name: "jeongju")
jeong.printInfo()

var student1 = Student(age: 19, name: "Minho") //상속을 받았기 때문에 생성자도 동일
student1.printInfo() //상속을 받아서 부모 클래스의 메서드 사용 가능
//실행 결과
//jeongju is 22
//Minho is 19

Student 클래스는 Person 클래스를 상속하여

Student 클래스 내부에 코드는 없지만 Person의 method와 property를 모두 가지고 있습니다.

따라서 Student 클래스로 만든 student1 instance는 Person 클래스의 생성자와 method를 사용할 수 있는 것이죠.


super 키워드

자식 클래스에서는 가끔 부모 클래스의 method를 호출해야 할 때가 있습니다.

super는 이런 상황에서 사용하는 키워드입니다.

 

super 예시

class Person {
    var name = "Unknown"
    var age = 0
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    func printInfo() {
        print("\(name) is \(age)")
    }
}

class Student: Person {
    var grade = 0.0
    
    init(age: Int, name: String, grade: Double) {
        super.init(age: age, name: name) //부모 클래스 생성자 호출
        self.grade = grade
    }
    
    func printGrade() {
        print("\(name) is \(grade)")
    }
}
    
var student1 = Student(age: 19, name: "Minho", grade: 4.3)
student1.printInfo()
student1.printGrade()
//실행결과
//Minho is 19
//Minho is 4.3

Student 클래스 내부에 property와 생성자를 추가해보았습니다.

Student 클래스의 생성자에서 부모클래스인 Person 클래스의 생성자를 호출하고

자신의 property인 grade만 자신의 생성자에서 초기화합니다.

생성자를 예시로 보여드렸지만 여러 가지로 활용할 수 있으니 실제 앱을 만들면서 활용해보면 좋겠습니다.


override

부모 클래스의 method를 상황에 맞게 수정이 필요할 때가 있습니다.

이럴 땐 해당 method를 overriding하면 됩니다.

 

똑같은 method 이름, 똑같은 parameter, 똑같은 return 타입을 갖도록 해야 하고

func 앞에 override 키워드를 쓰면 됩니다.

그러면 부모 클래스의 원본 method보다 자식 클래스에서 overriding 한 method가 우선적으로 호출된다.

 

만약 override 키워드를 안 쓰면 

"overriding declaration requires an 'override' keyword" 에러가 나니 참고해주세요.

 

class Person {
    var name = "Unknown"
    var age = 0
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    func printInfo() {
        print("\(name) is \(age)")
    }
}

class Student: Person {
    var grade = 0.0
    
    init(age: Int, name: String, grade: Double) {
        super.init(age: age, name: name) //부모 클래스 생성자 호출
        self.grade = grade
    }
    
    override func printInfo() { //Person 클래스의 printInfo()를 오버라이딩
        print("\(name) is \(age) and and has a \(grade) grade")
    }
}
    
var student1 = Student(age: 19, name: "Minho", grade: 4.3)
student1.printInfo()
//실행결과
//Minho is 19 and and has a 4.3 grade

Student 클래스에서는 부모 클래스의 printInfo()를 오버 라이딩하였습니다.

Student instance가 printInfo()를 호출하면 Person 클래스의 printInfo()가 아니라

Student 클래스의 printInfo()가 호출되어 결과가 출력됩니다.


extension

extension은 Swift의 클래스, 구조체, 열거형, protocol에 새로운 기능을 추가할 때 사용합니다.

자식 클래스를 생성하거나 참조하지 않고 기존 클래스에 method, initializer, computed property 등의

기능을 추가하기 위하여 사용합니다.

Swift 언어의 built-in 클래스와 iOS 프레임워크에 내장된 클래스에 기능을  추가할 때

extension을 이용하면 매우 효과적이라고 하네요.

 

extension은 아래 방법처럼 하시면 됩니다.

extension 기존 타입 이름 {
	//새로운 기능
}

 

extension 예시

extension Int {
    var squared: Int { //computed property 추가
        return self * self
    }
}

let intValue = 3
print(intValue.squared) //Int형 상수, 변수에서 사용 가능
print(4.squared) //Int형 값에서도 바로 사용 가능
//실행결과
//9
//16

저는 기본 자료형인 Int를 extension 하였습니다.

Int에 자신의 값을 2배로 하여 return 해주는 squared 메서드를 추가하였습니다.

원래는 없는 메서드를 extension을 통해 기능을 확장한 것이죠.

 

이렇게 확장한 것은 instance를 통해 호출할 수도 있고 실제 해당 자료형 값에서도 바로 사용이 가능합니다.


오늘은 객체 지향의 중요한 개념 중 하나인 상속에 대해 알아보았습니다.

아직 Swift 초보라 깊은 내용에 대해서는 다루지 못해서 아쉽습니다.

혹시 빠진 부분, 더 알면 좋을 부분이 있다면 댓글로 알려주세요.

열심히 공부하겠습니다.

 

감사합니다!


아직은 초보 개발자입니다.

더 효율적인 코드 훈수 환영합니다!

공감 댓글 부탁드립니다.

 

 

 

반응형