继承

继承用于在面向对象的编程中对“is-a”关系或子级关系进行建模。

指定继承关系

使用类声明中的 inherit 关键字指定继承关系。 以下示例显示了基本语法形式。

type MyDerived(...) =
    inherit MyBase(...)

一个类最多可以有一个直接基类。 如果不使用 inherit 关键字指定基类,则类隐式继承自 System.Object

继承的成员

如果类继承自另一个类,则派生类的用户可以使用基类的方法和成员,就好像它们是派生类的直接成员一样。

任何允许绑定和构造函数参数都专用于类,因此,无法从派生类访问。

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 子句的参数列表中。 所使用的值必须从提供给派生类构造函数的参数中确定。

以下代码显示了基类和派生类,其中派生类调用继承子句中的基类构造函数:

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())

有关对象表达式的详细信息,请参阅 对象表达式

创建对象层次结构时,请考虑使用歧视的联合而不是继承。 歧视联合还可以为共享通用整体类型的不同对象的不同行为建模。 单个区分联合通常不需要多个派生类,这些类是彼此的次要变体。 有关歧视工会的信息,请参阅 歧视联盟

另请参阅