Swifter {Swift Developer}

메뉴

고급진 클래스 이해하기

[이번 장의 목표]

  • 서브스크립트 이해하기
  • 상속 이해하기
  • 프로토콜 이해하기
  • 확장 이해하기
  • 연산자 오버로드 이해하기
  • 구조 이해하기

 

  1. 서브스크립트

클래스나 구조체는 서브스크립트(Subscript)를 정의할 수 있다. 클래스가 서브스크립트를 정의하면 배열이나 사전처럼 인덱스나 키 요소에 접근할 수 있다. 서비스크립트의 가장 간단한 정의방법은 다음과 같다. 이 정의된 형태는 서브스크립트 값만 받을 수 있다.

Exam클래스에는 String형 인수를 1개를 가지고 String형 값을 리턴 서브스크립트가 정의되어 있다.  다음으로 Exam클래스의 인스턴스를 생성하고 서브스크립트가 데이터를 검색하고 있다.

다음으로 인스턴스변수 e 뒤에 []을 붙이고 첨자로 “안녕”이라는 문자열을 지정하지만, 서브스크립트는 인수로서 이 “안녕”을 받고 내부적으로 문자열을 만들어 리턴한다. 따라서 “명준 안녕”이라고 출력된다.

 

(1) 여러 개의 서브스크립트

하나의 클래스에 인수와 리턴값의 형이 다른 서브스크립트를 여러가지로 정의할 수 있다.

String형의 인수 및 String형의 리턴값을 가지며 Int형 인수 2개와 리턴값을 가지는 서브스크립트내부에서 받아서 계산후 리턴하게 한다. 이처럼 서브스크립트가 여러 개 정의된 경우 호출자의 인수형과 인수 갯수에 따라 자동으로 호출되는 서브스크립트가 결정한다.

 

(2) 읽고 쓸수 있는 서브스크립트

이전까지는 서비스크립트를 사용하는 방법이 값을 가져오는 방법만 설명하고 있었다. 이제 읽고 쓸 수 있는 서브스크립트를 알아보자. 이것을 사용하게 되면 계산된 속성뿐만 아니라 subscript내부에서 get/set블록을 만든다. Get블록은 호출에 응답한 값을 전달하고 set블록은 호출을 통해 전달된 값을 처리한다.

서브스크립트가 호출을 통해 받은 값은 set블록 내부에서 newValue라는 특별한 변수에 들어간다. newValue 변수를 사용하지 않고 값을 얻게 하려면 set인수를 가지게 한다. Get블록은 서브스크립트에서 값을 얻을 때 처리를 설명하고 여기에 클래스 내에 정의된 배열 변수 data에 첨자를 지정하여 값을 얻을 수 있다.

Set블록은 서브스크립트에서 값을 할당할 때 처리를 설명한다. 이 예제에서는 배열의 insert메소드를 사용하여 서비스크립트가 값 newValue를 배열 data의 인덱스 위치에 삽입한다.  그리고 외부에서는 일반 배열과 같은 방식으로 서브스크립트를 통해 값을 대입하고 있다. 또한 첨자를 지정해서 설정한 값을 호출할수도 있다.

 

(3) 여러 가지 인덱스 사용하기

서브스크립트는 여러가지 첨자를 동시에 사용하여 값을 지정할 수 있다.

Exam클래스는 Ine형, a, b의 두값을 인수ㅇ로 취하는 이니셜라이저가 정의되어 있다. 이니셜라이저로 받은 a, b값을 이용하여 IceBox라는 배열 크기를 설정하고 배열의 각 요소의 초기값을 0으로 한다.  참고로 Array에서 count인수로 지정한 값이 배열크기가 되고 repeatedValue내용은 모두 같은 값으로 초기화한다.

클래스에 정의된 서브스크립트는 인수로 a, b 두값을 받아 배열 IceBox의 각 요소값을 읽고 쓸수 있다. Exam큻래스의 인스턴스 생성은 외부에서 e 변수를 선언해서 처리학 욌고 a 5, b 9이라는 값을 전달하여 총 45개의 값을 사용할 수 있게 하였다. 서브스크립트 값의 대입은 그 다음에 이루어지고 e[3, 6]과 같은 3개의 값을 넣고 있다.

 

  1. 상속

(1) 상위클래스와 하위클래스

기존 클래스의 기능을 계승받고 새로운 클래스를 만드는 것을 상속이라고 한다. 이때 상속클래스를 상위클래스 또는 슈퍼클래스라고 하며 상속에 의해 생성된 클래스를 하위클래스 또는 서브클래스라고 한다.

스위프트 언어를 포함 다양한 언어들은 하나의 클래스가 상속할 수 있는 클래스는 한 개뿐이지만 상속한 클래스를 더 상속할 수 있다.

상속의 장점은 새로운 클래스를 만들 떄 상속 기능을 계승할 수 있다는 것이다. 예로 PC를 한대 조립한다고 생각해 보자. PC를 나타내는 컴퓨터 클래스를 만들자. 컴퓨터 내부에는 다양한 구성 제품들이 포함된다. 이를 좀더 객체지향적으로 생객해보면, CPU, SSD, 메모리를 가진 기본적인 컴퓨터를 상위 클래스로 두고 이 상위클래스를 상속한 하위클래스를 만들고 거기에 USB-C, 7.1ch Sound, Bluetooth 4, Wi-Fi등의 기능을 추가하여 다양한 구성을 가진 컴퓨터를 쉽게 만들 수 있을 것이다.

위 예제에서는 Computer라는 상위클래스를 정의하고 이 클래스는 유지형 속성 cpu, memory, ssd와 이니셜라이저, msg메소드로 구성한다.

이 Computer를 계승한 PCType1 하위클래스를 정의한다. Computer를 계승하고 있기 때문에 PCType1에서는 usb3, wifi를 포함한 5가지 속성을 가질 수 있고 상위에 있던 메소드와 이니셜라이저도 상속받는다. PCType2 하위클래스도 Computer를 계승받고 usb3, wifi, bluetooth4등을 포함해서 사용이 가능해 진다. PCType2는 이니셜라이저를 가지고 있지 않지만 상위클래스에 이니셜라이저가 정의되어 있기 때문에 인스턴스 생성시 이니셜라이저가 사용된다.

 

(2) 메소드 재정의

상위클래스에 정의된 메소드는 하위클래스에서도 사용할 수 있지만, 경우에 따라 기능 일부를 변경해서 사용하고 싶은 경우가 있다. 이런 경우 상위 클래스에서 정의된 메소드와 같은 이름을 가진 메소드를 하위클래스에 정의해서 구현이 가능하며 이것을 메소드 재정의라고 말한다.

오버라이드(override)할 경우 override키워드를 지정한다.

앞서 사용했던 Computer 클래스의 msg메소드를 하위클래스 PCType2에서 재정의해 보자.

상위 클래스의 msg메소드를 재정의하고 있기 때문에 msg메소드를 사용하면 PCType2클래스의 msg메소드를 호출하여 “명준님의 견적서”가 표시된다.

 

(3) 상위 클래스의 메소드 사용

super키워드를 사용하면 하위클래스에서 상위클래스의 메소드를 사용할 수 있다.

상위클래스 Computer의 msg메소드를 호출하는데 이렇게 super키워드를 사용하면 하위클래스에서 상위클래스의 맴버를 사용할 수 있다.

 

(4) 상속과 재정의 금지하기

만든 클래스가 상속되지 않게 하고 싶거나 그 안에 정의된 메소드를 재정의하지 않도록 하고 싶은 경우가 있다. 이런 경우 final키워드를 사용하여 재정의되는 것을 막을 수 있다.

다음은 메소드를 재정의하지 못하도록 할 경우의 예제를 살펴보자. 클래스 상속 금지를 한 것처럼 메소드 정의 앞에 final키워드를 추가한다. 이렇게 선언하면 상위클래스가 가진 msg메소드를 재정의할 수 없기 때문에 하위클래스 PCType1이나 PCType2에서 msg를 재정의할 수 없게 된다.

  1. 프로토콜

프로토콜은 클래스에 적용하는 규칙을 정의하는 것이다. 여기에서 규칙은 클래스에 구현하는 속성과 메소드 정의를 말한다. 프로토콜은 적용하는 클래스는 프로토콜에 포함된 속성과 메소드를 구현해야 하며 구현하지 않으면 오류가 발생한다. 또한, Java, C# 프로토콜과 유사한 기능으로 Interface가 있다.

포로토콜은 아래와 같이 정의한다. 단, 프로토콜은 속성이나 메소드명, 형 인수는 명기하지만 내용은 구현하지 않는다.

drawProtocol은 선을 그리는 것을 가정한 프로토콜로 그리기에 필요한 속성으로 위치정보를 나타내는 x, y와 크기를 나타내는 width, height를 정의한다. 그리고 그리기를 할 draw메소드를 정의한다. 단, draw메소드 내용에는 아무것도 작성하지 않다는 것을 기억하자.

이렇게 정의된 프로토콜은 클래스에서 적용할 때 다음과 같이 선언한다.

이 예제는 drawProtocol을 적용한 rectangle클래스를 정의한다. Rectangle클래스 내부에 drawProtocol이 가진 모든 맴버를 구현해야 한다. 구현하지 않으면 프로토콜 규칙을 지키지 않는 것으로 오류가 발생한다.

 

  1. 확장

(1) 클래스 확장

확장을 사용하면 클래스를 수정하지 않고 기능을 추가할 수 있다.

SumAdd클래스에는 이니셜라이저에서 받은 2개의 숫자를 덧셈한 결과를 리턴하는 add메소드가 정의되어 있다. 그리고 클래스 외부에서 SumAdd클래스 기능을 확장하여 수식 표시를 위한 dispExp메소드가 추가되어 있다. 확장된 기능 사용법은 일반클래스 기능과 동일하기 때문에 처음부터 정의된 것처럼 사용이 가능하다.

 

(2) 표준 클래스 확장하기

스위프트 언어에서 제공되는 표준 클래스에 대해서도 자유롭게 기능 확장이 가능하다.

(3) 연산자 오버로드

기존의 연산자는 함수나 메소드처럼 오버로드 할 수 있다. 예로 + 연산자의 숫자끼리를 합산 연산자이지만, 문자열끼리 사용한다면 문자열을 연결하게 된다. 또한 연산자 오버로드는 클래스 외부에서 정의한다.

카페 남성과 여성 회원을 관리하는 클래스 CafeMember가 있다고 가정해 보자. 이 클래스의 이니셜라이저는 남성과 여성 인원수를 받는다. 속성 male, female은 각각의 남성수와 여성수를 total을 통해 합계를 낸다.

이제 CafeMember클래스에 +연산자 오버로드를 추가해서 CafeMember클래스의 인스턴스끼리 덧셈을 할 수 있도록 한다. 연산자 오버로드는 클래스 정의 외부 함수로 정의한다. 인수는 연산대상의 클래스를 지정하지만, 인수갯수는 오퍼레이터에 의해 결정된다.  +연산자는 2개의 항을 얻는 연산자에 대한 인수 2개를 지정할 수 있다.

이제  더하기 위한 카페맴버를 구성하기 위해 cafe1, cafe2인스턴스를 생성한다. 두개를 더해 cafetotal에 대입한다. Cafetotal.total속성을 사용하여 두개 카페맴버 총수를 표시한다.

그리고 == 연산자를 오버로드하여 카페인원수가 동일한지를 판정할 수 있다.

== 연산자를 사용하여 값을 비교할 수 있다.

  1. 구조체

스위프트 언어에서는 클래스와 유사한 구조체라는 것이 있다. 구조체는 클래스뿐만 아니라 속성, 이니셜라이저, 메소드, 서브스크립트를 정의할 수 있다. 다만 클래스와 구조체는 다음과 같은 차이점이 있다.

  • 구조체는 값형 클래스는 참조형이다.
  • 구조체는 상속할수 없다.
  • 구조체는 디이니셜라이저를 정의할 수 없다.

구조체를 정의할 경우 struct키워드를 사용한다.

personInfo 구조체를 정의하고 name, age, gender라는 3가지 속성을 가진 구조체이다.그리고 pi라는 구조체 변수를 정의하고 맴버변수를 인수로 가지는 이니셜라이저가 자동으로 정의되어 속성은 클래스처럼 점을 찍어 사용하고 다시 값을 각각 할당도 가능하다.

Facebook Comments

카테고리:   Swift

댓글

죄송하지만 댓글은 닫혀 있습니다.