23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

The Swift Programming Language - Inheritance(継承)をまとめる

Posted at

The Swift Programming Language をまとめるトップ

Inheritance(継承)

クラスはメソッドやプロパティを他のクラスから継承することができる
何かを継承しているクラスの事をサブクラスと言い継承されたクラスをスーパークラスと言う

クラスはすべてのメソッドやプロパティやサブスクリプトにアクセスでき、また、オーバライドもできる
他プロパティオブザーバーなども継承できたりする
保存型や算出プロパティ問わずオブザーバーは追加できる(以下で説明)

Defining a Base Class(ベースクラスの定義)

何も継承していないクラスのことをベースクラスという

以下、 Vehicle がベースクラスとして定義され、 numberOfWheelsmaxPassngers がプロパティとして宣言されている
description メソッドはプロパティの解説をしている

class Vehicle {
    var numberOfWheels: Int
    var maxPassengers: Int
    func description() -> String {
        return "\(numberOfWheels) ホイール; 上限乗車数\(maxPassengers)人"
    }
    init() {
        numberOfWheels = 0
        maxPassengers = 1
    }
}

Veicle クラスはイニシャライザーを定義し初期値を設定している
サブクラスによってどのようにプロパティを設定するか紹介する必要がある

イニシャライザーはメソドッドのシンタックスとほぼ同等
インスタスのプロパティが正しい初期値をもっているかなど確実なものにするために必要

以下、引数無しが一番シンプルな書き方

init() {
	// ここに初期設定を書く
}

インスタンスの生成は以下の様になる

let someVehicle = Vehicle()

Subclassing

クラスを継承してサブクラスでリファインする

以下が継承の方法で : を使っ継承できる

class SomeClass: SomeSuperclass {
	// クラスの定義を書く
}

Vehicle クラスの特徴を継承して新たに Bicyle クラスを定義する

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

super.init() を呼び出し Bicycle で値が修正される前に初期値を設定し、 numberOfWheels のみ書き換える
自転車なので maxPassengers は 1 のまま

NOTE
ObjCとは異なりイニシャライザーはデフォルトで継承されない
詳細は Initializer Inheritance and Overriding.

description メソッドも以下の様に継承されている

let bicycle = Bicycle()
println("自転車: \(bicycle.description())")
// prints "自転車: 2 ホイール; 上限乗車数 1 人

サブクラスもまた継承することができる

class Tandem: Bicycle {
	init() {
		super.init()
		maxPassengers = 2
    }
}

maxPassengers のみアップデートしている

Note
サブクラスは初期化中に変数のみ修正することができる
継承された定数はサブクラスで修正することができない

Tandem のインスタンをつくって、 description を実行してみると上限乗車のみ更新されていることがわかる

let tandem = Tandem()
println("Tandem: \(tandem.description())")
// prints "Tandem: 2 ホイール; 上限乗車数 2 人

description() 最上位で定義されているメソッドも有効

Overriding

オーバライディング(Overriding)はインスタンスメソッドやクラスメソッドやインスタンスプロパティやサブスクリプトの実装をサブクラスでカスタマイズすること

override

継承する対象の定義の頭に override を記述するとオバーライドする
override をつけないで同じ名前のものを定義しようとしたら同一のもがあると言うエラーがでる
何も記述しない場合は、スーパークラスのものがそのまま継承される

Accessing Superclass Methods, Properties, and Subscripts

super

オーバーライドしたメソッドやプロパティやサブスクリプトからスパークラスの実装をそのまま使いた時に super を使ってアクセスすることができる

  • オーバーライドしたメッソドは オーバーライドしているメソッドを super.someMethod() で呼び出す事ができる
  • オーバーライドしたプロパティは、 オーバーライドしている getter, setter で supper.someProperty を呼び出す事ができる
  • オーバーライドしたサブスクリプトは、 オーバライドしているサブスクリプトの実装内で supper[someIndex] を呼び出す事ができる

Overriding Methods(メソッドのオーバーライド)

新しく Car サブクラスを Veicle クラスを継承して description() をオーバーライドしているクラスを定義してみる

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

Double で speed という保存型プロパティを宣言、初期値は 0.0
あと、イニシャライザーも定義して継承したプロパティの値を設定する
override プリフィックスを使って description() をオーバライドする
super.descrioption をオーバライドしたメッソド内で呼び出して新たな実装をしている

If you create a new instance of Car, and print the output of its description method, you can see that the description has indeed changed:

let car = Car()
println("車: \(car.description())"
// prints "車: 4 ホイール; 上限乗車数 5 人 0.0 mph で移動中"

Overriding Properties(プロパティのオーバーライド)

保存型、算出型プロパティ問わず、 getter と setter を使ってオーバーライドを記述することができる
プロパティの型と名前を正しく指定する必要がある

read-only プロパティをオーバライドして read-write プロパティとして getter と setter を定義することはできる
その代わり、 read-write プロパティは read-only として定義することはできない

NOTE
例えば継承した getter のプロパティーを変更したくない場合、そのまま super クラスのプロパティを以下の例の様に返すと良い

スピードの制限を設定したクラスを生成してみる

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

set 内で min を使って speed プロパティを調整する
min は引数のどちらかが小さい場合、小さい方を返すグローバル関数

let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0
println("スピード上限: \(limitedCar.description())")
// prints "スピード上限: 4 ホイール; 上限乗車数 5 人 40.0 mph で移動中"

Overriding Property Observers(プロパティオブザーバーのオーバーライド)

プロパティオブザーバーもオバーライドすることができる

NOTE
定数と read-only の算出プロパティは監視することができない
値を新たにセットすることができないので、監視する必要がない
オバーライドされている setter と プロパティオブザーバーも、そこで監視すればよいのでオブザーバを再定義することができない

オートマッティクの車クラス定義して値の変化を監視してみる

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

didSet 内で 10.0 ごとに適切なギアを自動でセットしている

let automatic = AutomaticCar()
automatic.speed = 35.0
println("オートマ車: \(automatic.description())")
// prints "オートマ車: 4 ホイール; 上限乗車数 5 人 40.0 mph で移動中 ギア 4"

Preventing Overrides(オーバーライドを防ぐ)

@final

@final class, @final var, $final func, @final class func, @final subscript と @final を付けてスーパークラス側で継承を防ぐこともできる
@final をオーバーライドしようとするとコンパイルエラーになる

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?