0
2

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 3 years have passed since last update.

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

Last updated at Posted at 2020-12-17

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

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

##定義方法

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


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

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


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では複数のクラスから継承する多重継承は禁止されています。

###定義方法

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


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

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

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

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

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


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()メソッドに上書き(オーバーライド)した方が楽だよね。
ということになるのでオーバーライドしてみます。


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内の処理内容は以下と同様になります。


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

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

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


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キーワードをつけることにより、
そのクラスを継承したクラスを定義することを禁止します。


class SuperClassA {}
final class SuperClassB {}

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

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

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

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

後編はコチラ
-> 【Swift】型の種類〜クラス後編〜

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

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?