Menu
Coddy logo textTech

イニシャライザとsuper

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 24/57。

サブクラスがデフォルト値のない格納プロパティを追加する場合は、独自のイニシャライザが必要です。まず独自のプロパティを設定し、その後、super.init(...) を使ってスーパークラスのイニシャライザを呼び出します。

class Animal {
    let name: String
    init(name: String) { self.name = name }
}

class Bird: Animal {
    let canFly: Bool

    init(name: String, canFly: Bool) {
        self.canFly = canFly
        super.init(name: name)
    }
}

let p = Bird(name: "Pip", canFly: false)
print("\(p.name) \(p.canFly)")

出力:

Pip false

順序が重要です。super.init が実行される前にサブクラスのプロパティに値が設定されていなければならず、継承したプロパティはその後でのみ使用できます。Swift はこれをコンパイル時にチェックします。

init(name: String, canFly: Bool) {
    // print(self.name)      // エラー: self が super.init より前に使用されている
    self.canFly = canFly     // 1. 自身のプロパティ
    super.init(name: name)   // 2. スーパークラス
    print(self.name)         // 3. これですべてが使用可能
}

サブクラスが独自のイニシャライザを定義すると、スーパークラスのイニシャライザを継承しなくなります。サブクラスは、同じパラメータを持つイニシャライザをオーバーライドし、override init として指定することもできます。

class Timer {
    var seconds: Int
    init(seconds: Int) { self.seconds = seconds }
}

class SafeTimer: Timer {
    override init(seconds: Int) {
        super.init(seconds: max(0, seconds))
    }
}

print(SafeTimer(seconds: -5).seconds)
print(SafeTimer(seconds: 30).seconds)

出力:

0
30

階層の各レベルは自身の部分を初期化し、残りをスーパークラスに引き渡します。そのため、チェーン内のすべてのプロパティには、正確に一度ずつ値が設定されます:

class Vehicle {
    let wheels: Int
    init(wheels: Int) { self.wheels = wheels }
}

class Car: Vehicle {
    let seats: Int
    init(seats: Int) {
        self.seats = seats
        super.init(wheels: 4)
    }
}

class Taxi: Car {
    let company: String
    init(company: String) {
        self.company = company
        super.init(seats: 5)
    }
}

let t = Taxi(company: "City Cabs")
print("\(t.company): \(t.wheels) wheels, \(t.seats) seats")

出力:

City Cabs: 4 wheels, 5 seats
challenge icon

チャレンジ

簡単

Product は name と price(セント単位)を格納します。格納プロパティ percent を持つサブクラス DiscountedProduct を宣言してください。そのイニシャライザは name、price、percent を受け取り、percent を格納し、パーセント分をすでに割り引いた価格(小数点以下切り捨て)で super.init を呼び出します。0〜100の範囲外の percent は0として扱います。DiscountedProduct に、tea: 450 (10% off) を返すメソッド label() を追加してください。

提供されたコードは name,price,percent の行を読み取り、それぞれについて DiscountedProduct を作成し、label() を出力します。

コードは Product.swift と DiscountedProduct.swift に記述します。main.swift には提供された入出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    let p = line.split(separator: ",").map { String($0) }
    let item = DiscountedProduct(name: p[0], price: Int(p[1])!, percent: Int(p[2])!)
    print(item.label())
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Swiftプレイグラウンド