12. 상속(inheritance)

클래스는 다른 클래스에서 메서드, 프로퍼티, 그리고 다른 특성을 상속 가능하다. 클래스가 다른 클래스에서 상속될 때 상속하는 클래스를 하위 클래스라고 하고(subclass), 상속된 클래스를 상위 클래스(superclass)라고 한다. 스위프트에서 클래스는 상위 클래스에 속하는 메서드, 프로퍼티, 서브스크립트 접근이 가능하며 이들을 동작 수정하기 위해 재정의한 버전을 제공가능하다.

기본 클래스(basic class)

다른 클래스에서 상속하지 않은 클래스를 기본 클래스(basic class)라고 한다. 스위프트에서는 상위 클래스 지정없이 정의한 클래스는 자동 기본클래스이다.

class Vehicle {
	var currentSpeed = 0.0
    var description : String {
    	return "traveling at \(currentSpeed) miles per hour)"
    }
    
   	func makeNoise() {
    	// do nothing
    }
}
// 다음과 같이 일반적으로 메서드 프로퍼티를 소유한 가운데 선언된 클래스를 기본 클래스라고 한다.

하위 클래스(subclass)

기존 클래스를 반으로 새로운 클래스를 만드는 작업이다. 하위 클래스는 기존 클래스의 특성을 상속하므로 수정이 가능하다. 하위클래스의 특성을 추가 또한 가능하다. 하위 클래스가 상위 클래스의 속성을 가졌다는 것을 의미하기 위하여 콜론으로 구분하고 상위 클래스의 이름을 기술해준다.

class SomeSubClass : SomeSuperClass {
	//	하위 클래스 정의가 들어간다
}

class Bicycle : Vehicle {
	var hasBasket = false
}
// 이 새로운 클래스는 Vehicle 클래스를 상속하는 Bicycle이라는 하위 클래스를 정의한다.
//이 하위 클래스는 상위 클래스에 있는 currentSpeed, description 등의 프로퍼티와 
//makeNoise() 메서드 등의 모든 특성을 자동으로 소유하게 된다.

let bicycle = Bicycle()
bicycle.hasBasket = true
//다음과 같이 클래스 인스턴스를 생성 후 프로퍼티에 접근도 가능하다.

bicycle.currentSpeed = 15.0
//상속된 currentSpeed 프로퍼티를 수정할 수 있다.
//하위 클래스는 그 자체로 하위클래스화 가능하다.

class Tandem : Bicycle {
	var currentNumberOfPassenger = 0
}

//이 하위 클래스는 자전거 클래스를 다시 상속받는다.
//이 하위 클래스는 스스로의 상위 클래스인 Vehicle, Bicycle 두 클래스의 모든 프로퍼티, 메서드를 사용 가능해진다.

let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
//다음과 같이 명시하지 않아도 전부 접근이 가능하다.

재정의(overriding)

  1. 하위 클래스는 상위클래스에서 상속할 인스턴스 메서드, 프로퍼티, 타입 프로터피 등의 자체 사용자 구현을 제공한다. 상속될 특성 앞에 override키워드를 추가하면 재정의가 가능하다.
  2. 상위 클래스의 메서드, 프로퍼티 및 서브 스크립트 접근은 super접두어를 통해서 상위 클래스의 버전을 구현하는 것이 가능하다. 예를 들어서 someMethod()라고 재정의 된 메서드는 재정의한 메서드 구현 내에 super.someMethod()를 호출하여 상위 클래스의 메서드 구현이 가능하다. someProperty라고 재정의된 프로퍼티는 getter와 setter구현 내에서 super.someProperty로 상위 클래스 버전의 someProperty를 접근 가능하다.
  3. 상속된 인스턴스 또는 타입 메서드를 재정의하여 하위 클래스네에서 맞춤형 대체 구현이 가능하다.
class Tarin : Vehicle {
	override func makeNoise() {
    	print("CHOO CHOO")
    }
}
// 다음과 같이 새로운 인스턴스 생성 후 makeNoise메서드를 호출 히 Train하위 클래스 메서드가 호출된다.

 let train = Train()
 train.makeNoise()
 //추추! 를 출력한다.
 
  1. 프로퍼티의 재정의는 재정의 부분으로 setter를 제공 시 getter도 제공해야 한다. 재정의 한 getter내에서 상속된 프로퍼티 값을 수정하고 싶지 않을 경우 someProperty가 재정의 하는 프로퍼티 이름에서 super.someProperty를 통해 상속값을 간단히 전달 가능하다.
class Car : Vehicle {
	var gear = 1
   	override var description : String {
    	return super.description + "in gear \(gear)"
    }
}
//여기에서 description 프로퍼티 재정의는 vehicle의 description 프로퍼티를 반환하는 
//super.description호출로 시작한다. 그 다음 유저의 기어정보를 추가한다.

let car  = Car()
car.currentSpeed = 25.0
var.gear = 3
print("Car : \(car.description)")
//다음과 같은 경우 25.0 마일과 3을 출력한다.기존 디스크립션에 추가한 문장을 출력하게 되는 것이다.
  1. 상속된 프로퍼티에 프로퍼티 관찰자를 추가하기 위해서 프로퍼티 재정의 사용이 가능하다. 이것은 기존 구현된 프로퍼티에 상관없이 프로퍼티 값 변경에 따른 알림을 받을 수 있다.
class AutomaticCar : Car {
	override var currentSpeed : Double {
    	didSet {
        	gear = Int(currentSpeed / 10.0) + 1
        }
    }
}
//여기에서 AutomaticCar인스턴스에 currentSpeed 프로퍼티를 설정할 때마다 
//didSet관찰자는 새로운 속도에 적절한 기어를 인스턴스의 gear에 설정한다. 

let automatic = Automatic()
automatic.currentSpeed = 35.0
 // gear를 4로 설정하게 된다.
  1. 재정의 방지는 final키워드를 통해서 가능하다. 재정의를 방지하고 싶은 경우 메서드, 프로퍼티, 서브 스크립트 키워드 전에 final 수정자를 작성한다(final var, final func, final class...) 하위 클래스에서 final 메서드나 프로퍼티 등을 재정의하는 경우 에러가 발생한다. 클래스 정의에 class전 final키워드를 통해서 전체를 final로 표시 가능하다. 이 경우 이 클래스를 상속하려는 모든 시도는 에러가 발생한다.

좋은 웹페이지 즐겨찾기