【Swift】型の種類〜クラス前編〜

#クラス とは
クラスは構造体と似た構造を持つ型になります。

構造体との大きな違いは２つ挙げられます。
**１つ、参照型である
２つ、継承が可能である**

##定義方法

クラスの定義には`classキーワード`を使用します。

```swift

class クラス名 {
   クラスの定義
}
```

型を構成する要素であるメソッドやプロパティ、イニシャライザは
クラスでも全て利用可能で、{ }内に定義することができます。

```swift

class Sample {
    var value: Int
    var status: String
    
     init(value: Int, status: String) {
         self.value = value
         self.status = status
     }
    
    func printStatus() {
        print("value: \(value)\nstatus: \(status)")
    }
}


let a = Sample(value: 123, status: "abc")
a.printStatus()

実行結果
value: 123
status: abc
```

##継承
 
継承とは、新たなクラスを定義する時に、
**他のクラスのメソッドやプロパティ、イニシャライザなどの型を再利用する仕組みです。**

継承というくらいなので、
再利用ではなく引き継ぐといった方がいいかもしれません。

継承先のクラスは継承元のクラスと共通する動作を定義する必要がなく、
継承元のクラスとの差分のみを定義すれば済みます。

継承元のクラスは、継承先のクラスの**スーパークラス**
継承先のクラスは、継承元のクラスの**サブクラス**と言います。

基本的に継承先のクラスは継承先のクラスの内容を
さらに詳しく定義したものになります。

**なお、Swiftでは複数のクラスから継承する多重継承は禁止されています。**

###定義方法

クラスに継承関係を定義する場合は、
クラス名の後に`： スーパークラス`を追加します。

```swift

class クラス名: スーパークラス名 {
   クラスの定義
}
```

次のサンプルコードでは、
継承元のクラス(スーパークラス)のクラス名をVehicle(乗り物)とし
継承先のクラス(サブクラス)のクラス名をCar(自動車)としました。

**継承先のCarクラスでは継承元のVehicleクラスで定義された
nameプロパティやprintProfile( )メソッドを扱うことができます。**

Vehicleクラスでは新たに、
kindプロパティとnewPrintProfile( )メソッドを定義しました。

newPrintProfile( )メソッドでは、Vehicleクラスで定義された
printProfile( )メソッドを呼び出しています。

```swift

class Vehicle {
    let name: String
    
    var message: String {
        return "乗り物の名前：\(name)"
    }
    
    init(name: String) {
        self.name = name
    }
    
    func printProfile() {
        print(message)
    }
}

class Car: Vehicle {
    var kind: String
    
    init(name: String, kind: String) {
        self.kind = kind
        super.init(name: name)
    }
    
    func newPrintProfile() {
        printProfile()
        print("乗り物の種類：\(kind)")
    }
}

let car = Car(name: "LEXUS LS", kind: "自動車")
car.printProfile()
print("----")
car.newPrintProfile()

実行結果
乗り物の名前：LEXUS LS
----
乗り物の名前：LEXUS LS
乗り物の種類：自動車
```

このように、継承を使うことにより重複する記述を省くことができます。
なので、似たクラスを多く定義する場合はうまく継承関係を作れると便利です。

##オーバーライド

オーバーロードとオーバーライドで名前が似ていますが、
オーバーロードは、異なる型の引数や戻り値を取る同名のメソッドを複数用意し、
引数に渡される型や戻り値の代入先の型に応じて実行するメソッドを切り替える手法です。

**オーバーライドは、スーパークラスで定義されているプロパティやメソッドなどの要素を
サブクラスで再定義する手法のことを指します。**

オーバーライドが可能なプロパティは、
**インスタンスプロパティ**と後述する**クラスプロパティ**のみになります。

つまり、スタティックプロパティはオーバーライドすることができません。

オーバーライドを行うためには、
`overrideキーワード`を使用してスーパークラスで定義されている要素を再定義します。

先ほどのサンプルコードを一部オーバーライドに修正します。

`newPrintProfile()メソッド`内の処理で、`printProfile()`が記述されています。

printProfile()メソッドの処理に
新しい処理`print("乗り物の種類：\(kind)")`を追加していた状態です。

新しいnewPrintProfile()メソッドを定義するくらいなら
printProfile()メソッドに上書き(オーバーライド)した方が楽だよね。
ということになるのでオーバーライドしてみます。

```swift

class Vehicle {
    let name: String
    
    var message: String {
        return "乗り物の名前：\(name)"
    }
    
    init(name: String) {
        self.name = name
    }
    
    func printProfile() {
        print(message)
    }
}

class Car: Vehicle {
    var kind: String
    
    init(name: String, kind: String) {
        self.kind = kind
        super.init(name: name)
    }
    
    // printProfileをオーバーライド
    override func printProfile() {
        super.printProfile()
        print("乗り物の種類：\(kind)")
    }
}

let car = Car(name: "LEXUS LS", kind: "自動車")
car.printProfile()

実行結果
乗り物の名前：LEXUS LS
乗り物の種類：自動車
```

オーバーライドする前のコードでは、
car.printProfile( )の結果は乗り物の名前しか出力されませんでした。

しかし、オーバーライド後にcar.printProfile( )を実行すると、
乗り物の名前に加え、乗り物の種類が出力されました。

printProfile( )メソッドに`super.printProfile()`と書かれています。
superとはスーパークラス(継承元)のことを指します。

つまり、スーパークラス(Vehicle)のprintProfile( )を実行と読み取れます。
それに加えて、上書きされた`print("乗り物の種類：\(kind)”)`も実行されます。

printProfile内の処理内容は以下と同様になります。

```swift

print(message)   // super.printProfile()の内容
print("乗り物の種類：\(kind)")
```

###finelキーワード
finalキーワードは、継承可能な要素の前に記述することにより、
その要素がサブクラスで**オーバーライドされることを禁止**できます。

次のサンプルコードから、
finelキーワードをつけていないメソッドがオーバーライトできますが、
finalキーワードをつけているメソッドはオーバーライドできないことがわかります。

```swift

class SuperClass {
    func methodA() {}
    final func methodB() {}
}

class SubClass: SuperClass {
    override func methodA() {}
    override func methodB() {}   // コンパイルエラー
}
```

エラー内容：`Instance method overrides a 'final' instance method`
和訳：インスタンスメソッドは「final」インスタンスメソッドをオーバーライドします

クラス自体にfinalキーワードをつけることにより、
そのクラスを継承したクラスを定義することを禁止します。

```swift

class SuperClassA {}
final class SuperClassB {}

class SubClassA: SuperClassA {}
class SubClassB: SuperClassB {}   // コンパイルエラー
```

エラー内容：`nheritance from a final class 'SuperClassB'`
和訳：最終クラス「スーパークラス」からの継承

継承されてはいけないクラスやメソッドなどがあった場合は、
finalキーワードをつけて継承を阻止するようにしましょう。

もっと書きたいことがあったのですが、
かなりの量になりそうでしたので前編と後編に分けたいと思います。

後編はコチラ
-> [【Swift】型の種類〜クラス後編〜](https://qiita.com/onishiApp/items/aa8b8a7bf225f3a8452e)

以上、最後までご覧いただきありがとうございました。