Swift - 方法重寫



重寫是面向物件程式語言中一個非常常見的概念。使用重寫,我們可以重新實現超類中的方法或屬性在子類中。它允許我們擴充套件繼承的行為。在重寫方法或屬性時,我們提供子類中的新實現,而不是使用超類中的實現。在 Swift 中,我們可以重寫超類的方法或屬性。

訪問超類的方法、屬性和下標

super”關鍵字用作字首來訪問在超類中宣告的方法、屬性和下標。

方法重寫 訪問方法、屬性和下標
方法 super.somemethod()
屬性 super.someProperty()
下標 super[someIndex]

Swift 中重寫的規則

以下是一些你在重寫時應該遵循的規則:

  • 子類中重寫的方法或屬性必須具有與超類中相同的簽名(名稱、引數和返回型別)。

  • 使用super關鍵字從重寫方法中的超類呼叫重寫的實現。

  • 使用override關鍵字重寫屬性。我們可以重寫儲存屬性和計算屬性。

  • 重寫方法或屬性的訪問級別不能比基類中重寫方法或屬性的訪問級別更嚴格。不允許使用私有方法重寫公共方法。因此,在重寫之前始終檢查訪問修飾符。

Swift 中的方法重寫

在 Swift 中,我們可以重寫方法。重寫方法意味著子類可以為在基類中已定義的方法提供不同的實現。或者我們可以說,我們可以在子類中自定義超類方法的行為。

子類中重寫的方法必須具有與基類相同的簽名(名稱、引數和返回型別),編譯器將根據物件的型別確定呼叫哪個方法。此外,子類中重寫方法的訪問級別必須與超類中方法的訪問級別相同或更寬鬆。

重寫方法是透過在子類中使用override關鍵字來定義的。此關鍵字放置在函式定義的開頭。它告訴編譯器該方法將重寫超類的方法。如果我們沒有指定override關鍵字,則編譯器將給出錯誤。

語法

以下是方法重寫的語法:

override func methodName(Parameters) -> returntype {
   Statement
   return parameters
}

示例

Swift 方法重寫的程式。

// Super class
class cricket {
   // Method
   func show() {
      print("Welcome to Swift Super Class")
   }
}

// Sub class
class tennis: cricket {
   // Overriden Method
   override func show() {
      print("Welcome to Swift Sub Class")
   }
}

// Creating instance of subclass
let tennisinstance = tennis()

// Accessing the override method
tennisinstance.show()

輸出

它將產生以下輸出:

Welcome to Swift Sub Class

屬性重寫

Swift 支援屬性重寫。與方法重寫一樣,屬性重寫也為子類提供了一種自定義在基類中已定義的屬性實現的方式。我們可以說,使用屬性重寫,我們可以為該屬性提供我們自己的 getter 和 setter,或者新增屬性觀察器,這使得重寫屬效能夠觀察屬性值何時更改。

子類中重寫屬性的型別必須與基類中屬性的名稱和型別相同。這樣編譯器就可以根據物件的型別確定呼叫哪個屬性(超類屬性或重寫屬性)。子類中重寫方法的訪問級別必須與超類中屬性的訪問級別相同或更寬鬆。

重寫屬性是透過在子類中使用override關鍵字來定義的。此關鍵字放置在屬性定義的開頭。它告訴編譯器該屬性將重寫超類的屬性。如果我們沒有指定override關鍵字,則編譯器將給出錯誤。

語法

以下是屬性重寫的語法:

override var propertyName: type{
   // Statement
}

示例

Swift 屬性重寫的程式。

// Superclass
class mySuperClass {

   // Property
   var language: String{
      return "C++"
   }
}
// Subclass
class mySubClass: mySuperClass {

   // Override Property
   override var language: String{
      return "Swift"
   }
}

// Creating an instance of a subclass
let obj = mySubClass()

// Accessing the overridden property
print(obj.language)

輸出

它將產生以下輸出:

Swift

重寫屬性 getter 和 setter

Swift 允許使用者重寫子類屬性的 getter 和 setter,無論該屬性是儲存屬性還是計算屬性。重寫屬性的名稱和型別必須與基類中存在的屬性相同。這樣編譯器就知道你正在重寫基類的屬性。

在 Swift 中,我們可以透過在子類中重寫時同時提供 getter 和 setter,將只讀繼承屬性表示為讀寫屬性。而我們不允許將讀寫繼承屬性表示為只讀屬性。當為重寫屬性定義 setter 時,使用者也必須定義 getter。如果我們不希望在重寫 getter 中修改繼承屬性的值,則可以使用 'super.PropertyName' 從 getter 傳遞繼承的值,其中 PropertyName 表示重寫屬性的名稱。

示例

Swift 重寫屬性 getter 和 setter 的程式。

// Base Class
class Circle {
   var radius = 12.5
    
   // Property with getter
   var area: String {
      return "of rectangle for \(radius) "
   }
}

// Subclass
class Rectangle: Circle {
   var print = 7
    
   // Overriding the getter
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

// Creating instance
let rect = Rectangle()

// Accessing the properties
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

輸出

它將產生以下輸出:

Radius of rectangle for 25.0  is now overridden as 3

重寫屬性觀察器

當需要為繼承屬性新增新屬性時,Swift 4 中引入了“屬性重寫”的概念。這會在繼承屬性值更改時通知使用者。但是,重寫不適用於繼承的常量儲存屬性和繼承的只讀計算屬性。

示例

class Circle {
   var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

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

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

let sq = Square()
sq.radius = 100.0
print("Radius \(sq.area)")

輸出

當我們使用 playground 執行上述程式時,我們將得到以下結果:

Radius of rectangle for 25.0  is now overridden as 3
Radius of rectangle for 100.0  is now overridden as 21

阻止 Swift 中的重寫

Swift 提供了一個特殊的關鍵字來阻止重寫方法、屬性、下標甚至類,這個關鍵字被稱為final關鍵字。final 關鍵字明確指示指定的 方法、屬性、下標或類不能被子類重寫。如果使用者仍然嘗試重寫,則編譯器將給出錯誤。

final 關鍵字始終用於方法、屬性、下標或類的宣告之前。

語法

以下是阻止重寫的語法:

// For methods
final func methodName(Parameters) -> returntype{}

// For property
final var propertyName : type

// For subscript
final subscript(index: Int)->Elemnt{}

// For class
final class className{}

示例

阻止重寫的 Swift 程式。

// Base class
final class Circle {
   final var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

// Sub class
class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

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

錯誤

main.swift:12:17: error: property overrides a 'final' property
   override var area: String {
                ^
main.swift:4:8: note: overridden declaration is here
   var area: String {
       ^
main.swift:10:7: error: inheritance from a final class 'Circle'
class Rectangle: Circle {
      ^
main.swift:21:17: error: ambiguous use of 'area'
print("Radius \(rect.area)")
                ^
main.swift:12:17: note: found this candidate
   override var area: String {
                ^
main.swift:4:8: note: found this candidate
   var area: String {
       ^

由於超類宣告為 'final',其資料型別也宣告為 'final',因此程式不允許進一步建立子類,並將丟擲錯誤。

廣告