iBooks にある “The Swift Programming Language” の勉強メモ。Objective-C と C を普段書いている自分から、ちょっと馴染みがないものを特にまとめておきます。目次は こちら。
今回は、Inheritance に関して。
Inheritance
1. ベースクラス
クラスは、他のクラスを継承することができます。継承により、メソッド、プロパティ、またサブスクリプト等の特性を継承したクラスを作成できます。
1 2 3 4 5 6 7 8 9 10 11 | class Vehicle { var numberOfWheels: Int var maxPassengers: Int func description() -> String { return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers" } init() { numberOfWheels = 0 maxPassengers = 1 } } |
Swift では、NSObject のようなすべてのクラスのベースとなるクラスはありません。つまり、継承をせずにクラスを作成したクラスは、自動的にそのコンテキストにおいてベースクラスになります。上記の Vehicle クラスはこの記事の中でこれから紹介する例の全てのクラスのベースクラスになります。
2. サブクラス
クラスを継承するには、サブクラス宣言時にクラス名の名前の後に : で区切り、継承されるクラス名を書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Bicycle: Vehicle { init() { super.init() numberOfWheels = 2 } } class Tandem: Bicycle { init() { super.init() maxPassengers = 2 } } |
Objective-C と違い、initializer はデフォルトで継承されません。
3. オーバーライド
サブクラスは、継承されたインスタンスメソッド、クラスメソッド、インスタンスプロパティ、サブスクリプトを独自に実装し直すことができます。そのためには、override
キーワードを使用します。もし、override
を使用せずに、オーバーライドを試みるとコンパイラエラーになります。
また、スーパークラスのメソッドやプロパティ、サブスクリプトをオーバーライドする際に、スーパークラスの実装をその中で使いたい場合があると思います。この時には、super
キーワードを使用してアクセスできます。この Car サブクラスの例では、description メソッドをオーバーライドしています。また、この サブクラスの例では、description の中では、スーパークラスの サブクラスの例では、description メソッドを使用しています。
1 2 3 4 5 6 7 8 9 10 11 12 | 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" } } |
プロパティをオーバーライドをすることもできます。サブクラス内で、独自のセッター・ゲッターを作成できます。また、プロパティオブザーバー を追加することもできます。
まずは、独自のゲッター・セッターをみていきます。継承されたプロパティが Stored property でも、Computed property でも、ゲッター・セッターを作成できます。ゲッター・セッターを実装することにより、スーパークラスの read-only のプロパティを read-write プロパティに変更することができます。しかし、read-write プロパティを read-only プロパティに変更することはできません。プロパティをオーバーライドする際に、セッターを実装する時にはゲッターも実装しなければなりません。もし、ゲッターを修正する必要がない場合には、ただスーパークラスのプロパティを返します。下記の SpeedLimitedCar はこのセッターだけ変更したい場合の例です。
1 2 3 4 5 6 7 8 9 10 | class SpeedLimitedCar: Car { override var speed: Double { get { return super.speed } set { super.speed = min(newValue, 40.0) } } } |
次に、プロパティオブザーバーのオーバーライドをみていきます。継承されたコンスタント Stored プロパティ、継承された read-only Computed プロパティには、プロパティオブザーバーを追加することはできません。なぜならば、これらの値に対して新しく値を設定することは許されていません。したがって、willSet
や didSet
を実装することはありません。また、セッターのオーバーライドとプロパティオブザーバーは、同時に作成できません。プロパティの値の変化を監視し、さらにセッターをオーバーライドしている場合には、この監視する機能をそのオーバーライドしたセッターのコードの中に書いてください。
1 2 3 4 5 6 7 8 9 10 11 | 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)" } } |
この AutomaticCar の例では、プロパティオブザーバーを追加しています。スーパークラスの speed プロパティが変更された場合に、AutomaticCar のプロパティである gear を変更しています。
4. オーバーライドの防止
他の言語と同じように、メソッド・プロパティ・サブスクリプトがオーバーライドされることを禁止することができます。@final
キーワードを使用します。例えば、@final var
、 @final func
、 @final class func
、@final subsript
と使います。このように @final
されたものをサブクラスの中でオーバーライドしようとすると、コンパイルエラーになります。
また、クラス自体を継承されることが不適切な場合には、class
キーワードの前に @fianl
を使用します。これにより、このクラスからサブクラスを作成することができなくなります。