Arv
Arv används för att modellera "is-a"-relationen, eller undertypning, i objektorienterad programmering.
Ange arvsrelationer
Du anger arvsrelationer med hjälp av nyckelordet inherit
i en klassdeklaration. Det grundläggande syntaktiska formuläret visas i följande exempel.
type MyDerived(...) =
inherit MyBase(...)
En klass kan ha högst en direkt basklass. Om du inte anger en basklass med hjälp av nyckelordet inherit
ärver klassen implicit från System.Object
.
Ärvda medlemmar
Om en klass ärver från en annan klass är metoderna och medlemmarna i basklassen tillgängliga för användare av den härledda klassen som om de vore direkta medlemmar i den härledda klassen.
Alla let-bindningar och konstruktorparametrar är privata för en klass och kan därför inte nås från härledda klasser.
Nyckelordet base
är tillgängligt i härledda klasser och refererar till basklassinstansen. Den används som självidentifierare.
Virtuella metoder och åsidosättningar
Virtuella metoder (och egenskaper) fungerar något annorlunda i F# jämfört med andra .NET-språk. Om du vill deklarera en ny virtuell medlem använder du nyckelordet abstract
. Det gör du oavsett om du anger en standardimplementering för den metoden. En fullständig definition av en virtuell metod i en basklass följer därför det här mönstret:
abstract member [method-name] : [type]
default [self-identifier].[method-name] [argument-list] = [method-body]
Och i en härledd klass följer en åsidosättning av den här virtuella metoden det här mönstret:
override [self-identifier].[method-name] [argument-list] = [method-body]
Om du utelämnar standardimplementeringen i basklassen blir basklassen en abstrakt klass.
Följande kodexempel illustrerar deklarationen av en ny virtuell metod function1
i en basklass och hur du åsidosätter den i en härledd klass.
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
Konstruktorer och arv
Konstruktorn för basklassen måste anropas i den härledda klassen. Argumenten för basklasskonstruktorn visas i argumentlistan i inherit
-satsen. De värden som används måste bestämmas utifrån argumenten som skickas till den härledda klasskonstruktorn.
Följande kod visar en basklass och en härledd klass, där den härledda klassen anropar basklasskonstruktorn i ärv-satsen:
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
När det gäller flera konstruktorer kan följande kod användas. Den första raden i de härledda klasskonstruktorerna är inherit
-satsen och fälten visas som explicita fält som deklareras med nyckelordet val
. Mer information finns i Explicita fält: Nyckelordetval
.
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")
Alternativ till arv
Om en mindre ändring av en typ krävs bör du överväga att använda ett objektuttryck som ett alternativ till arv. I följande exempel visas användningen av ett objektuttryck som ett alternativ till att skapa en ny härledd typ:
open System
let object1 =
{ new Object() with
override this.ToString() = "This overrides object.ToString()" }
printfn "%s" (object1.ToString())
Mer information om objektuttryck finns i Objektuttryck.
När du skapar objekthierarkier bör du överväga att använda en diskriminerad union i stället för arv. Diskriminerade fackföreningar kan också modellera olika beteenden för olika objekt som delar en gemensam övergripande typ. En enda diskriminerad union kan ofta eliminera behovet av ett antal härledda klasser som är mindre variationer av varandra. Information om diskriminerade fackföreningar finns i Diskriminerade fackföreningar.