繼承

繼承是用來在物件導向程式設計中建立 "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())

如需物件運算式的詳細資訊,請參閱物件運算式

當您建立物件階層時,請考慮使用區分聯合,而不是使用繼承。 區分聯合也可以為共用通用整體型別的不同物件,建立不同行為的模型。 如果衍生類別是彼此的次要變體,單一區分聯合通常可避免一些衍生類別的需求。 如需區分聯合的詳細資訊,請參閱區分聯合

另請參閱