이번에는 클래스의 상속에 대한 개념에 대해서 알아보도록 하자.
이전에 클래스와 구조체의 차이에 대해서 확인을 하면서 클래스만의 고유의 상속에 대해서 알아보려고 한다.
상속
- 상속이란 부모가 자식에게 재산을 물려주는 행위라고 생각하면 편하다.
- 스위프트에서 상속은 다른 클래스로부터 메소트, 프로피터 또는 다른 특성을 상속받는 것을 의미한다.
- 한 클래스가 다른 클래스를 상속 받을 때에 상속받는 클래스는 자식 클래스 또는 서브 클래스라고 한다.
- 상속하는 클래스는 슈퍼클래스 또는 부모 클래스라고 한다.
- 상속은 스위프트에서의 다른 타입과 클래스를 구별짓는 클래스만의 특징이다.
- 서브 클래스는 슈퍼 클래스로부터 물려받는 메소드, 프로퍼티, 서브 스크립트를 호출 할 수 있다.
- 오버라이딩을 통해서 물려받은 메소드, 프로퍼티, 서브 스크립트 등을 자신만의 내용으로 재정의 할 수 있다.
- 상속받은 프로퍼티의 값이 변경되었을 때에 알려주는 프로퍼티 감시자도 구현할 수 있다.
- 부모 클래스에서 연산 프로퍼티로 정의한 프로퍼티나 저장 프로퍼티로 정의한 프로퍼티든 자식 클래스에서 프로퍼티 감시자를 구현할 수 있다.
이처럼 상속은 클래스만의 독특한 권한 또는 특징이다.
다른 언어들을 많이 사용한 개발자들이라면 주요 개념에 대해서는 매우 자세하게 알고 있을 것이지만 Swift로 처음 개발을 접하는 사람들에게 도움이 되고, 필자 또한 공부를 하려고 포스팅을 하기 때문에 보다 자세하게 정의를 해보았다.
글로만 설명을 할 경우에는 이해가 잘 되지 않기 때문에 소스를 통해서 하나하나 천천히 확인을 해보도록 하자.
우선 상속의 개념을 이해하기 위한 Animal 클래스를 정의하였다.
현재 해당 클래스는 아무것도 상속을 해주지도 않았고, 아무것도 상속을 받지 않았다. 이런 클래스를 베이스 클래스라고 부르기도 한다.
보통 개발자들은 하나하나 정확히 말하는 것을 싫어하는 사람들이 많기 때문에 실제 협업을 해서 개발할 때에는 굳이 베이스 클래스라고 부르진 않는다. 참고로만 알고 있으면 될 것 같다.
이제 상속을 해줄 부모 클래스를 만들었으니 해당 클래스를 상속받을 다른 클래스를 만들어보자.
우선 상속을 받을 서브클래스를 만드는 방법은 다음과 같다.
class 클래스 이름 : 부모 클래스 이름 { // 하위 클래스에 대한 정의 } |
이렇게 생성을 한다. 특별한 내용 없이 서브 클래스의 이름을 선언 하고 : 이후 상속을 받고자 하는 부모 클래스의 이름을 작성하면 된다.
슈퍼 클래스인 Animal 클래스를 상속받는 Cheetah 클래스를 선언했다. 위에서 언급한 사용 방법대로 : Animal 만 붙여줬다.
이렇게 상속을 받게 되면 실제로 Cheetah 클래스에 sex라는 성별 프로퍼티 밖에 없는것 같아 보이지만
부모 즉, Aniaml 클래스에서 선언된 변수와 메소를 모두 상속 받게 된다. Aniaml 클래스에서 정의한 speed 와 text를 사용할 수 있다는 의미이다.
한번 내용을 확인해보도록 하자.
좌측의 이미지를 확인해보면 이렇게 Cheetah에 대한 cheetah1의 인스턴스를 생성을 하고 사용을 하려고 했을 때에 슈퍼 클래스의 내용을 확인할 수 있다.
이제 우측의 이미지를 확인해보면 이전에 클래스에서 활용했다 싶이 동일하게 사용을 할 수 있다.
굳이 슈퍼클래스의 내용을 서브클래스에 동일하게 작성을 안해주고 동일한 내용으로 여러 클래스를 만들 필요가 없다는 의미이다.
그럼 이제 위에서 언급한 정의 중의 하나인 오버라이딩에 대해서 알아보도록 하자.
오버라이딩
- 서브 클래스는 슈퍼클래스에서 정의된 메소드, 프로퍼티, 서브 스크립트 등을 그대로 사용하지 않고, 자신만의 기능으로 변경하여 사용할 수 있다. 이를 오버라이딩이라고 한다.
- 오버라이딩을 사용하기 위해서는 오버라이드라는 키워드를 사용해줘야 한다.
- 만약 같은 이름의 정의가 슈퍼 클래스에 없는데 오버라이드 키워드를 사용하면 컴파일러 에러가 발생한다.
- 또한 슈퍼 클래스에 동일한 이름의 정의가 있는데 오버라이드 키워드를 사용하지 않으면 오류가 발생한다.
이번에도 소스를 통해서 내용 확인을 진행해보도록 하자.
좌측의 이미지는 우선 오버라이딩을 확인하기 위해서 슈퍼 클래스에 cry 라는 함수를 선언했다. 해당 함수를 사용할 경우 "해당 동물의 울음소리는 : " 라는 문구를 확인할 수 있도록 생성하였다.
그리고 cheeta1.cry()를 호출하였을 때에 해당 문구가 정상적으로 출력되는 것을 확인하였다. 이처럼 서브 클래스에서는 슈퍼 클래스의 메소드도 사용이 가능하다.
우측의 이미지는 슈퍼클래스의 cry 라는 메소드를 서브 클래스인 Cheetah에서 오버라이드 한 부분이다.
슈퍼클래스의 동일한 메소드를 작성할 경우에 해당 enter를 치면 자동으로 저렇게 선언해준다.
이렇게 슈퍼클래스의 내용을 오버라딩하면 된다.
오버라이드를 하기 전에는 슈퍼클래스의 메소드 내용인 "해당 동물의 울음소리는 : " 해당 내용이 출력이 되었지만, 오버라이드를 치타의 고유 울음소리인 "우에엥 우아옹" ( 그냥 필자가 유투브에서 치타 울음소리 들었을 때의 느낌... ) 이렇게 나오는 것을 확인할 수 있다.
이처럼 서브 클래스에서 굳이 슈퍼 클래스의 내용을 그대로 사용하고 싶지 않을 때에 이렇게 오버라이드를 해서 사용하면 된다.
그럼 이제 반대로 생각을 해보자. 그럼? 오버라이드를 한번 진행하면 슈퍼클래스의 내용은 절대로 못 쓰는건가? 이런 의문이 들 수도 있지만 실상은 그렇지 않다.
이제 오버라이드도 사용하고, 슈퍼클래스의 내용도 사용할 수 있도록 확인을 해보도록 하자.
이렇게 슈퍼 클래스의 메소드를 오버라이딩 된 구문이나, 클래스에서 사용하고 싶을 때에는 super. 이라는 키워드를 활용하면 된다.
해당 소스에서 super.cry() 부분을 활용하여 콘솔창에서는 "해당 동물의 울음소리는 : " 이런 내용까지 표기가 된 것을 확인할 수 있다.
서브 클래스에서는 슈퍼 클래스에서 상속받은 특성을 재정의 할수도 있고, 슈퍼 클래스의 특성을 활용하고자 할때에도 이렇게 사용할 수 있는 부분이다.
그럼 이제 추가로 슈퍼 클래스의 프로퍼티를 오버라이딩 해보도록 하자.
여기서 프로퍼티를 재정의 한다는 것은 프로퍼티 자체가 아니라 프로퍼티의 getter / setter / 프로퍼티 옵저버 등을 재정의 하는 것을 의미한다.
슈퍼 클래스 Animal의 text 프로퍼티를 재정의 해보았다.
소스 상의 내용을 확인해보면 체감 속도를 확인할 수 있는 변수를 생성하였고, 해당 변수를 슈퍼 클래스의 text 프로퍼티를 재정의 하여 해당 부분에서 사용을 하도록 만들어보았다.
슈퍼클래스의 재정의한 Cheetah 클래스의 text 프로퍼티에서는 위에서 확인했다 싶이 슈퍼클래스의 프로퍼티 내용도 활용할 수 있도록 생성을 하였다.
그럼이제 실행시켜보도록 하자.
이렇게 재정의 한 슈퍼 클래스의 프로퍼티를 다시 사용 했을 때에는 슈퍼 클래스의 메소드를 재정의 했을 때와 같이 정상적으로 중복되어서 사용할 수 있다는 것을 확인할 수 있다.
추가로 연산 프로퍼티, 저장 프로퍼티를 오바리이드 한 프로퍼티는 getter / setter를 가질 수 있고, 자식클래스에서 재정의하려는 프로퍼티는 슈퍼클래스 프로퍼티의 타입과 이름이 일치해야 한다. 슈퍼 클래스에서 read/write로 선언된 프로퍼티를 서브 클래스에서 read only로 오버라이드 할 수는 없지만, 슈퍼 클래스에서 read only 로 선언된 프로퍼티는 서브클래스에서 read / write 로 오버라이드 할 수 있다.
필자가 동물에 대해서는 정확히 모르지만 대충 Cheetah 클래스를 상속받는 Leopard 클래스를 생성하였다.
그리고 leopard 인스턴스를 생성했고, 하위에 하위 클래스를 상속받았지만 최상위 슈퍼 클래스와 슈퍼클래스의 프로퍼티를 사용할 수 있다.
해당 내용을 실행해보면 프로퍼티 재정의를 통해서 speed 값이 변경되면서 프로퍼티 옵저버에 의해 체감속도 speed 가 변경되게 사용할 수 있다.
상속된 프로퍼티에 오버라이드를 사용하면 프로퍼티 옵저버를 추가할 때는 상수 저장 프로퍼티나 read/only 연산 프로퍼티에는 프로퍼티 옵저버를 추가할 수 없다. 그 이유는 상수 저장 프로퍼티나 read only 연산 프로퍼티에는 값을 설정할 수 없기 때문에 willSet 이나 didSet을 사용할 수 없다.
마지막으로 메소드 프로퍼티, 타입 프로퍼티가 오버라이드 될 수 있도록 하는 것을 방지 할 수 있다.
이렇게 슈퍼클래스의 프로퍼티 나 메소드 앞에 final 을 입력할 경우에는 해당 프로퍼티를 재정의 할 수 없다.
이는 클래스 자체에 final 을 작성할 경우에는 상속을 받을 수는 있지만 상속을 해줄 수 없다. 해당 클래스의 서브클래스를 만들 수 없다는 의미이다.
이렇게 이번에는 상속에 대한 개념을 잡고 갔다. 많이 헷갈릴 수도 있겠지만 차근차근 충분한 테스트를 해보면 금방 이해가 될 것 같다.
'APPLE > Swift 문법' 카테고리의 다른 글
[ 기초 문법 ] Assert / Preconditions (0) | 2022.08.17 |
---|---|
[ 기초 문법 ] 타입 캐스팅 (0) | 2022.08.16 |
[ 기초 문법 ] 프로퍼티 (0) | 2022.08.11 |
[ 기초 문법 ] Init (0) | 2022.08.10 |
[ 기초 문법 ] 구조체와 클래스 (0) | 2022.08.09 |