Menu
Coddy logo textTech

サブクラス

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

継承を使うと、あるクラスを基にして別のクラスを構築できます。class Dog: Animalは、DogをスーパークラスであるAnimalのサブクラスにします。つまり、犬は動物のすべてのプロパティとメソッドに加えて、Dogが追加するものも持ちます。

class Animal {
    var name: String
    init(name: String) { self.name = name }
    func describe() -> String { "\(name) is an animal" }
}

class Dog: Animal {
    func fetch() -> String { "\(name) fetches the ball" }
}

let rex = Dog(name: "Rex")
print(rex.describe())
print(rex.fetch())

出力:

Rex is an animal
Rex fetches the ball

保存プロパティを追加しないサブクラスはスーパークラスのイニシャライザを継承します。そのため、Dog内にinitがなくてもDog(name:)が機能します。継承はis-a関係をモデル化します。すべての犬は動物なので、DogはAnimalが期待される場所で使用できます。

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

class Cat: Animal {}
class Dog: Animal {}

let pets: [Animal] = [Cat(name: "Tom"), Dog(name: "Rex")]
for pet in pets { print(pet.name) }

出力:

Tom
Rex

継承をサポートしているのはクラスだけです。構造体と列挙型は継承できません。クラスが持てるスーパークラスは最大1つですが、スーパークラスは複数のサブクラスを持つことができ、階層を形成します。

class Vehicle { var wheels = 0 }
class Car: Vehicle { }        // Car は Vehicle です
class Bike: Vehicle { }       // Bike は Vehicle です
// struct Truck: Vehicle { }  // error: 構造体は継承できません

すべてのサブクラスに共通するものはスーパークラスに置き、各サブクラスには違いだけを置きます。一方の型がもう一方の型の本当の意味での一種ではない場合、継承は適切な手段ではありません。もう一方の型を保持するプロパティのほうが適していることがよくあります。

class Shape {
    var name: String
    init(name: String) { self.name = name }
    func label() -> String { "a \(name)" }
}

class Square: Shape {
    var side = 1.0
    func area() -> Double { side * side }
}

let s = Square(name: "square")
s.side = 3
print(s.label())
print(s.area())

出力:

a square
9.0
challenge icon

チャレンジ

簡単

Employee は name と salary を保持し、給与をパーセンテージ分(切り捨て)増加させるメソッド raise(by:) を持ちます。保存プロパティ reports(名前の配列で、最初は空)とメソッド addReport(_:) を追加するサブクラス Manager を宣言し、報告者の人数を返すメソッド teamSize() も追加してください。

提供されたコードは、最初の行(name,salary)からマネージャーを作成し、後続の各名前を報告者として追加し、10%の昇給を行い、Ada earns 5500 and leads 2 を出力します。

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

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
let head = input[0].split(separator: ",").map(String.init)
let boss = Manager(name: head[0], salary: Int(head[1])!)
for name in input.dropFirst() { boss.addReport(name) }
boss.raise(by: 10)
print("\(boss.name) earns \(boss.salary) and leads \(boss.teamSize())")
quiz icon腕試し

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

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

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