지정 생성자와 편의 생성자의 자동 상속 규칙 (예외 상황)
지정 생성자 자동 상속의 예외 상황
- 하위 클래스에서 새로운 저장 속성이 추가되지 않았거나, 모든 저장 속성이 기본값으로 초기화된 경우
- 이 경우, 상위 클래스의 모든 지정 생성자가 자동으로 상속된다
- 하위 클래스에서 지정 생성자를 정의하거나 재정의하지 않으면, 자동 상속이 발생한다
편의 생성자 자동 상속의 예외 상황
- 지정 생성자가 자동으로 상속된 경우 (
super.init()이 잘 동작하는 경우)
- 하위 클래스에서 상위 클래스의 모든 지정 생성자를 재정의하여 초기화 실패의 가능성이 없어진 경우
- 상위 클래스의 지정 생성자가 모두 상속되면, 상위 클래스의 편의 생성자도 자동으로 상속된다
지정 생성자와 편의 생성자의 상속 예외 예제
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
let food1 = Food(name: "Pasta")
let food2 = Food()
print("Food1: \(food1.name)")
print("Food2: \(food2.name)")
Food 클래스는 name이라는 저장 속성을 가지고 있다
name은 필수적으로 초기화되어야 하므로 지정 생성자에서 초기화된다
convenience init() 편의 생성자는 지정 생성자를 호출하여 초기화 작업을 간편하게 한다
- 편의 생성자는 지정 생성자를 호출하는 방식으로 초기화 위임을 수행한다
- 이 클래스는 상속 시 특별한 예외사항이 없지만, 편의 생성자는 자동 상속되지 않는다
지정 생성자 재정의 및 편의 생성자 상속 예외 예제
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
let ingredient1 = RecipeIngredient()
let ingredient2 = RecipeIngredient(name: "Tomato")
let ingredient3 = RecipeIngredient(name: "Egg", quantity: 12)
print("Ingredient1: \(ingredient1.name), Quantity: \(ingredient1.quantity)")
print("Ingredient2: \(ingredient2.name), Quantity: \(ingredient2.quantity)")
print("Ingredient3: \(ingredient3.name), Quantity: \(ingredient3.quantity)")
RecipeIngredient 클래스는 Food 클래스를 상속받아 새로운 저장 속성 quantity를 추가한다
quantity는 새로 추가된 저장 속성이므로 자동 상속 규칙이 깨진다
- 지정 생성자 (
init(name: String, quantity: Int))를 정의하여 quantity를 초기화해야 한다
- 상위 클래스의 지정 생성자를 호출하기 위해 (
super.init()) 반드시 사용해야 한다
- 지정 생성자
init(name:)을 편의 생성자로 재정의하여 초기화 과정을 단순화한다
- 이 클래스는 상속 시 자동 상속되지 않는다 (
quantity 초기화 필요)
지정 생성자 및 편의 생성자의 자동 상속 예제
자동 상속 예제 (기존의 지정 생성자 자동 상속)
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
let item1 = ShoppingListItem()
let item2 = ShoppingListItem(name: "Bread")
let item3 = ShoppingListItem(name: "Milk", quantity: 2)
item1.purchased = true
print(item1.description)
print(item2.description)
print(item3.description)
- ShoppingListItem 클래스는 RecipeIngredient 클래스를 상속한다.
- 새로운 저장 속성 purchased는 기본값 false로 초기화된다
- 기본값이 제공되기 때문에 초기화의 실패 가능성이 없다
- 따라서, 상위 클래스의 지정 생성자 및 편의 생성자가 모두 자동으로 상속된다
- 자동 상속이 발생하는 이유
• 새로운 저장 속성 purchased가 기본값으로 초기화됨
• 상위 클래스의 지정 생성자가 자동으로 상속될 수 있음
상위의 지정 생성자를 모두 재정의하는 경우
class FullyDefinedShoppingListItem: RecipeIngredient {
var purchased: Bool
override init(name: String, quantity: Int) {
self.purchased = false
super.init(name: name, quantity: quantity)
}
override init(name: String) {
self.purchased = false
super.init(name: name)
}
}
let itemA = FullyDefinedShoppingListItem(name: "Apple", quantity: 5)
let itemB = FullyDefinedShoppingListItem(name: "Orange")
print("Item A: \(itemA.name), Quantity: \(itemA.quantity), Purchased: \(itemA.purchased)")
print("Item B: \(itemB.name), Quantity: \(itemB.quantity), Purchased: \(itemB.purchased)")
FullyDefinedShoppingListItem 클래스는 RecipeIngredient 클래스를 상속한다
- 모든 지정 생성자를 재정의하여 초기화한다
- 이 경우, 상위 클래스의 지정 생성자가 자동 상속되지 않기 때문에 직접 구현해야 한다
- 상위 클래스의 지정 생성자가 모두 재정의되면, 상위 클래스의 편의 생성자가 자동으로 상속된다
요약
- 새로운 저장 속성을 추가하지 않거나 모든 저장 속성이 기본값으로 초기화되면, 지정 생성자가 자동으로 상속된다
- 상위 클래스의 지정 생성자를 모두 재정의하면, 상위 클래스의 편의 생성자가 자동으로 상속된다
- 자동 상속은 초기화 실패의 가능성이 없을 때만 발생한다