繼承是用來在面向物件程序設計中建立「is-a」關聯性或子系結的模型。
指定繼承關聯性
您可以在類別宣告中使用 inherit 關鍵詞來指定繼承關聯性。 基本語法形式會顯示在下列範例中。
type MyDerived(...) =
inherit MyBase(...)
類別最多可以有一個直接基類。 如果您未使用 inherit 關鍵字指定基類,類別會隱含繼承自 System.Object。
繼承的成員
如果類別繼承自另一個類別,則衍生類別的使用者可以使用基類的方法和成員,就好像它們是衍生類別的直接成員一樣。
任何 let 系結和建構函式參數都是類別的私人,因此無法從衍生類別存取。
關鍵詞 base 可在衍生類別中使用,並參考基類實例。 其會像自我標識碼一樣使用。
虛擬方法和覆寫
相較於其他 .NET 語言,虛擬方法(和屬性)在 F# 中的運作方式稍有不同。 若要宣告新的虛擬成員,請使用 abstract 關鍵詞。 不論您是否為該方法提供預設實作,您都會這麼做。 因此,基類中虛擬方法的完整定義會遵循下列模式:
abstract member [method-name] : [type]
default [self-identifier].[method-name] [argument-list] = [method-body]
在衍生類別中,此虛擬方法的覆寫會遵循下列模式:
override [self-identifier].[method-name] [argument-list] = [method-body]
如果您省略基類中的預設實作,基類會變成抽象類。
下列程式代碼範例說明基類中新虛擬方法 function1 的宣告,以及如何在衍生類別中覆寫它。
type MyClassBase1() =
let mutable z = 0
abstract member function1: int -> int
default u.function1(a: int) =
z <- z + a
z
type MyClassDerived1() =
inherit MyClassBase1()
override u.function1(a: int) = a + 1
建構函式和繼承
基類的建構函式必須在衍生類別中呼叫。 基底類別建構函式的引數會出現在 inherit 子句的引數清單中。 所使用的值必須從提供給衍生類別建構函式的自變數中判斷。
下列程式代碼顯示基類和衍生類別,其中衍生類別會呼叫 inherit 子句中的基類建構函式:
type MyClassBase2(x: int) =
let mutable z = x * x
do
for i in 1..z do
printf "%d " i
type MyClassDerived2(y: int) =
inherit MyClassBase2(y * 2)
do
for i in 1..y do
printf "%d " i
在多個建構函式的情況下,可以使用下列程序代碼。 衍生類別建構函式的第一行是 inherit 子句,而且欄位會顯示為以 關鍵詞宣告的 val 明確欄位。 如需詳細資訊,請參閱 明確字段: val 關鍵詞。
type BaseClass =
val string1 : string
new (str) = { string1 = str }
new () = { string1 = "" }
type DerivedClass =
inherit BaseClass
val string2 : string
new (str1, str2) = { inherit BaseClass(str1); string2 = str2 }
new (str2) = { inherit BaseClass(); string2 = str2 }
let obj1 = DerivedClass("A", "B")
let obj2 = DerivedClass("A")
繼承的替代方案
如果需要稍微修改類型,請考慮使用物件表達式作為繼承的替代方案。 下列範例說明使用物件表示式作為建立新衍生類型的替代方法:
open System
let object1 =
{ new Object() with
override this.ToString() = "This overrides object.ToString()" }
printfn "%s" (object1.ToString())
如需物件表達式的詳細資訊,請參閱 物件表達式。
當您建立物件階層時,請考慮使用歧視的等位,而不是繼承。 歧視聯集也可以建立不同物件不同行為模型,這些對象共用通用整體類型。 單一歧視聯集通常不需要一些衍生類別彼此的次要變化。 如需歧視等位的相關信息,請參閱 歧視聯集。