Vererbung
Vererbung wird zur Modellierung der „ist-ein“-Beziehung (Untertypen) in objektorientierter Programmierung verwendet.
Angeben von Vererbungsbeziehungen
Sie geben Vererbungsbeziehungen mithilfe des Schlüsselworts inherit
in einer Klassendeklaration an. Die grundlegende syntaktische Form wird im folgenden Beispiel gezeigt.
type MyDerived(...) =
inherit MyBase(...)
Eine Klasse kann höchstens eine direkte Basisklasse haben. Wenn Sie keine Basisklasse mithilfe des Schlüsselworts inherit
angeben, erbt die Klasse implizit von System.Object
.
Geerbte Elemente
Wenn eine Klasse von einer anderen Klasse erbt, sind die Methoden und Member der Basisklasse für Benutzer der abgeleiteten Klasse so verfügbar, als wären sie direkte Member der abgeleiteten Klasse.
Alle let-Bindungen und Konstruktorparameter sind für eine Klasse privat. Der Zugriff darauf kann daher nicht von abgeleiteten Klassen aus erfolgen.
Das Schlüsselwort base
ist in abgeleiteten Klassen verfügbar und verweist auf die Basisklasseninstanz. Es wird wie der Selbstbezeichner verwendet.
Virtuelle Methoden und Außerkraftsetzungen
Virtuelle Methoden (und Eigenschaften) funktionieren in F# im Vergleich zu anderen .NET-Sprachen etwas anders. Um einen neuen virtuellen Member zu deklarieren, verwenden Sie das Schlüsselwort abstract
. Dies geschieht unabhängig davon, ob Sie eine Standardimplementierung für diese Methode bereitstellen. Daher folgt eine vollständige Definition einer virtuellen Methode in einer Basisklasse dem folgenden Muster:
abstract member [method-name] : [type]
default [self-identifier].[method-name] [argument-list] = [method-body]
In einer abgeleiteten Klasse folgt eine Außerkraftsetzung dieser virtuellen Methode dem folgenden Muster:
override [self-identifier].[method-name] [argument-list] = [method-body]
Wenn Sie die Standardimplementierung in der Basisklasse auslassen, wird die Basisklasse zu einer abstrakten Klasse.
Das folgende Codebeispiel zeigt die Deklaration einer neuen virtuellen Methode function1
in einer Basisklasse und ihre Außerkraftsetzung in einer abgeleiteten Klasse.
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
Konstruktoren und Vererbung
Der Konstruktor für die Basisklasse muss in der abgeleiteten Klasse aufgerufen werden. Die Argumente für den Basisklassenkonstruktor sind in der Argumentliste in der inherit
-Klausel enthalten. Die verwendeten Werte müssen aus den Argumenten bestimmt werden, die für den abgeleiteten Klassenkonstruktor bereitgestellt werden.
Der folgende Code zeigt eine Basisklasse und eine abgeleitete Klasse, wobei die abgeleitete Klasse den Basisklassenkonstruktor in der inherit-Klausel aufruft:
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
Bei mehreren Konstruktoren kann der folgende Code verwendet werden. Die erste Zeile der abgeleiteten Klassenkonstruktoren ist die inherit
-Klausel, und die Felder werden als explizite Felder angezeigt, die mit dem Schlüsselwort val
deklariert werden. Weitere Informationen finden Sie unter Explizite Felder: Das Schlüsselwort 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")
Alternativen zur Vererbung
In Fällen, in denen eine geringfügige Änderung eines Typs erforderlich ist, sollten Sie einen Objektausdruck als Alternative zur Vererbung verwenden. Das folgende Beispiel zeigt die Verwendung eines Objektausdrucks als Alternative zum Erstellen eines neuen abgeleiteten Typs:
open System
let object1 =
{ new Object() with
override this.ToString() = "This overrides object.ToString()" }
printfn "%s" (object1.ToString())
Weitere Informationen zu Objektausdrücken finden Sie unter Objektausdrücke.
Wenn Sie Objekthierarchien erstellen, sollten Sie anstelle von Vererbung eine diskriminierte Union verwenden. Diskriminierte Unions können auch unterschiedliche Verhaltensweisen verschiedener Objekte modellieren, die einen allgemeinen Gesamttyp gemeinsam verwenden. Eine einzelne diskriminierte Union kann häufig die Notwendigkeit einer Reihe abgeleiteter Klassen beseitigen, die geringfügige Variationen voneinander sind. Informationen zu diskriminierten Unions finden Sie unter Diskriminierte Unions.