読者です 読者をやめる 読者になる 読者になる

【Swift】Appleの新言語「Swift」のリファレンスを読む(10) - Inheritance

注意

  • あくまでメモ書きなので細かい部分を端折りますし、色々間違ってるかもしれません。ちゃんとした内容は原文を読んでね。
  • コード例は基本的に原文からそのまま引用していますが、ちょっとした注釈をつけたり、統合したりしています。
  • SyntaxHighlighterが対応してないので微妙に読みにくいです。SyntaxHighlighterはこちらのものを使用させて頂いてます。
  • 他言語にそっくりな部分でも指摘しない。(自戒)

Inheritance(継承)

ようやく折り返し地点ってとこですかね。今回は継承です。継承とは何か、とか、そう言う話をするつもりは一切ないです。いつも通りのオブジェクト指向プログラミングにおける継承だと思えばそれで大体あっています。

Classes and Structuresの章でもちょっとだけ書きましたが、継承出来るのはClassだけです。まぁ、Extentionがチートくさいのであんまり問題ないと思います。

Defining a Base Class

まずは基底クラス(Base Class)を作りましょう。

Swiftでは一番大元の基底クラス(所謂「Objectクラス」のようなもの)を明示的に継承することは出来ません。何も継承しなければ、自動的にその大元の基底クラスを継承することになります。

class Vehicle {
    var numberOfWheels: Int
    var maxPassengers: Int
    func description() -> String {
        return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
    }

    init() {
        numberOfWheels = 0
        maxPassengers = 1
    }
}

基底クラスの説明をするための例が「Vehicle」とは…。まるで旧世紀の参考書ですね。

ま、そんなことはどうでもよくて、initって書いてある部分がイニシャライザ(コンストラクタ)です。クラスのインスタンスを取得するとまずここが呼ばれることになります。

let someVehicle = Vehicle()

見ての通りnewキーワードのようなものはありません。さぁサクサク次へ進みましょう。

Subclassing

それじゃあサブクラスを作りましょう。

class Bicycle: Vehicle {
    init() {
        super.init()
        numberOfWheels = 2
    }
}

何一つ説明する気が起きません。単にイニシャライザをオーバーライドして、VehicleのプロパティであるnumberOfWheelsの値を書き換えているだけです。

親クラスのプロパティなら何でも変えられるわけではなく、letで宣言されてるものは再代入不可能です。当たり前だ。

Bicycleから親クラスのVehicleが持つメソッドを呼べば当然こうなります。

let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers

Overriding

Swiftの継承でオーバーライド出来るものはインスタンス / クラスメソッドインスタンスプロパティ、サブスクリプトです。イニシャライザは書き忘れたんでしょうか。まぁあれは必須だしな…。

明示的に親クラスの実装を呼び出したいときはsuperを付けます。super.someMethod()とか、super.somePropertyとか、super[someIndex]みたいな感じです。

じゃあまずはメソッドをオーバーライドしてみましょう。

class Car: Vehicle {
    var speed: Double = 0.0
    
    init() {
        super.init()
        maxPassengers = 5
        numberOfWheels = 4
    }
    override func description() -> String {
        return super.description() + "; "
            + "traveling at \(speed) mph"
    }
}

let car = Car()
println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph

見ての通りoverrideがキーワード化されてる方の言語です。まぁ今時されてない方が珍しいですね。

省略可能かどうかは書いてありませんでした。多分無理なんじゃないかな。

[2014/06/13追記]

次章でさらっと書かれていました。イニシャライザのみoverrideキーワードは省略可能とのこと。

[2014/06/13追記ここまで]

次に先ほど作成したCarクラスのspeedなるプロパティをオーバーライドしてみましょう。

class SpeedLimitedCar: Car {
    override var speed: Double {
    get {
        return super.speed
    }
    set {
        super.speed = min(newValue, 40.0)
    }
    }
}

let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())")
// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph

プロパティだけでなく、プロパティオブザーバもオーバーライド出来ます。

class AutomaticCar: Car {
    var gear = 1
    
    override var speed: Double {
    didSet {
        gear = Int(speed / 10.0) + 1
    }
    }
    
    override func description() -> String {
        return super.description() + " in gear \(gear)"
    }
}

let automatic = AutomaticCar()
automatic.speed = 35.0
println("AutomaticCar: \(automatic.description())")
// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4

ちなみにRead OnlyなプロパティをRead Writeに変えることは出来るが、Read WriteなプロパティをRead Onlyにすることは出来ないとのこと。

Preventing Overrides

@finalと言うAttributeをつけるとサブクラスでの継承を禁止することが出来ます。

@final classとか、@final funcみたいな感じですね。オーバーライド可能なものには全部つけることが出来ます。

他の章に比べて説明量がものすごく少ないですが、次章が結構ヘビーなので一旦ここで切ることにします。