Swift 継承

継承とは、あるクラスが別のクラスのメソッドとプロパティを取得することだと理解できます。

あるクラスが他のクラスを継承するとき、継承するクラスをサブクラス、継承されるクラスをスーパークラス(または親クラス)と呼びます。

Swiftでは、クラスはスーパークラスのメソッド、プロパティ、添え字スクリプトを呼び出してアクセスでき、さらにそれらをオーバーライドできます。

また、クラスが継承したプロパティにプロパティオブザーバを追加することもできます。


基底クラス

他のクラスを継承していないクラスを基底クラス(Base Class)と呼びます。

次の例では、学生(stname)と各科目の点数(mark1、mark2、mark3)を表す基底クラス StudDetails を定義しています。

class StudDetails {
    var stname: String!
    var mark1: Int!
    var mark2: Int!
    var mark3: Int!
    init(stname: String, mark1: Int, mark2: Int, mark3: Int) {
        self.stname = stname
        self.mark1 = mark1
        self.mark2 = mark2
        self.mark3 = mark3
    }
}
let stname = "swift"
let mark1 = 98
let mark2 = 89
let mark3 = 76

let sds = StudDetails(stname:stname, mark1:mark1, mark2:mark2, mark3:mark3);

print(sds.stname)
print(sds.mark1)
print(sds.mark2)
print(sds.mark3)

上記のプログラムを実行すると、出力は次のようになります。

swift
98
89
76

サブクラス

サブクラスとは、既存のクラスを基にして新しいクラスを作成することを指します。

あるクラスのスーパークラスを指定するには、スーパークラス名をサブクラス名の後にコロン(:)で区切って記述します。構文は次のとおりです。

class SomeClass: SomeSuperclass {
    // 类的定义
}

インスタンス

次の例では、スーパークラス StudDetails を定義し、サブクラス Tom でそれを継承しています。

class StudDetails
{
    var mark1: Int;
    var mark2: Int;
    
    init(stm1:Int, results stm2:Int)
    {
        mark1 = stm1;
        mark2 = stm2;
    }
    
    func show()
    {
        print("Mark1:\(self.mark1), Mark2:\(self.mark2)")
    }
}

class Tom : StudDetails
{
    init()
    {
        super.init(stm1: 93, results: 89)
    }
}

let tom = Tom()
tom.show()

上記のプログラムを実行すると、出力は次のようになります。

Mark1:93, Mark2:89

オーバーライド(Overriding)

サブクラスは、継承したインスタンスメソッド、クラスメソッド、インスタンスプロパティ、または添え字スクリプトを使用して独自のカスタム機能を実装できます。この動作をオーバーライド(overriding)と呼びます。

override キーワードを使用してオーバーライドを実装できます。

スーパークラスのメソッド、プロパティ、添え字スクリプトへのアクセス

super プレフィックスを使用すると、スーパークラスのメソッド、プロパティ、添え字スクリプトにアクセスできます。

オーバーライド メソッド、プロパティ、添え字スクリプトへのアクセス
メソッド super.somemethod()
プロパティ super.someProperty()
添え字スクリプト super[someIndex]

メソッドとプロパティのオーバーライド

メソッドのオーバーライド

サブクラスでは、override キーワードを使用してスーパークラスのメソッドをオーバーライドできます。

次の例では、show() メソッドをオーバーライドしています。

class SuperClass {
    func show() {
        print("这是超类 SuperClass")
    }
}

class SubClass: SuperClass  {
    override func show() {
        print("这是子类 SubClass")
    }
}

let superClass = SuperClass()
superClass.show()

let subClass = SubClass()
subClass.show()

上記のプログラムを実行すると、出力は次のようになります。

这是超类 SuperClass
这是子类 SubClass

プロパティのオーバーライド

継承したプロパティが格納型か計算型かに関係なく、カスタムの getter(または setter)を提供して、任意の継承プロパティをオーバーライドできます。

サブクラスは、継承したプロパティが格納型か計算型かを知りません。継承したプロパティに名前と型があることだけを知っています。したがって、プロパティをオーバーライドするときは、その名前と型の両方を記述する必要があります。

注意点:

  • オーバーライドするプロパティで setter を提供する場合は、必ず getter も提供する必要があります。

  • オーバーライド版の getter で継承したプロパティの値を変更したくない場合は、super.someProperty を使用して継承した値を直接返すことができます。ここで someProperty はオーバーライドするプロパティの名前です。

次の例では、スーパークラス Circle とサブクラス Rectangle を定義し、Rectangle クラスでプロパティ area をオーバーライドしています。

class Circle {
    var radius = 12.5
    var area: String {
        return "矩形半径 \(radius) "
    }
}

// 继承超类 Circle
class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

上記のプログラムを実行すると、出力は次のようになります。

Radius 矩形半径 25.0  ,但现在被重写为 3

プロパティオブザーバのオーバーライド

プロパティのオーバーライドで、継承したプロパティにプロパティオブザーバを追加できます。これにより、継承したプロパティの値が変更されたときに、それを監視できます。

注意:継承した定数格納型プロパティ、または継承した読み取り専用の計算型プロパティには、プロパティオブザーバを追加できません。

class Circle {
    var radius = 12.5
    var area: String {
        return "矩形半径为 \(radius) "
    }
}

class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}


let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("半径: \(rect.area)")

class Square: Rectangle {
    override var radius: Double {
        didSet {
            print = Int(radius/5.0)+1
        }
    }
}


let sq = Square()
sq.radius = 100.0
print("半径: \(sq.area)")
半径: 矩形半径为 25.0  ,但现在被重写为 3
半径: 矩形半径为 100.0  ,但现在被重写为 21

オーバーライドの防止

final キーワードを使用して、それらがオーバーライドされるのを防ぐことができます。

final メソッド、プロパティ、または添え字スクリプトをオーバーライドすると、コンパイル時にエラーが発生します。

キーワード class の前に final 特性(final class)を追加することで、クラス全体を final としてマークできます。このようなクラスは継承できず、継承しようとするとコンパイルエラーになります。

final class Circle {
    final var radius = 12.5
    var area: String {
        return "矩形半径为 \(radius) "
    }
}
class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("半径: \(rect.area)")

class Square: Rectangle {
    override var radius: Double {
        didSet {
            print = Int(radius/5.0)+1
        }
    }
}

let sq = Square()
sq.radius = 100.0
print("半径: \(sq.area)")

上記の例では final キーワードを使用してオーバーライドを許可していないため、実行するとエラーになります。

error: var overrides a 'final' var
    override var area: String {
                 ^
note: overridden declaration is here
    var area: String {
        ^
error: var overrides a 'final' var
    override var radius: Double {
                 ^
note: overridden declaration is here
    final var radius = 12.5
              ^
error: inheritance from a final class 'Circle'
class Rectangle: Circle {
      ^
その他の拡張