Ereditarietà

L'ereditarietà viene usata per modellare la relazione "is-a" o la sottotipizzazione nella programmazione orientata agli oggetti.

Specifica delle relazioni di ereditarietà

È possibile specificare le relazioni di ereditarietà usando la inherit parola chiave in una dichiarazione di classe. Il formato sintattico di base è illustrato nell'esempio seguente.

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

Una classe può avere al massimo una classe base diretta. Se non si specifica una classe base usando la inherit parola chiave , la classe eredita in modo implicito da System.Object.

Membri ereditati

Se una classe eredita da un'altra classe, i metodi e i membri della classe base sono disponibili per gli utenti della classe derivata come se fossero membri diretti della classe derivata.

Le associazioni let e i parametri del costruttore sono privati di una classe e pertanto non è possibile accedervi da classi derivate.

La parola chiave base è disponibile nelle classi derivate e fa riferimento all'istanza della classe base. Viene usato come l'identificatore automatico.

Metodi virtuali ed override

I metodi virtuali (e le proprietà) funzionano in modo leggermente diverso in F# rispetto ad altri linguaggi .NET. Per dichiarare un nuovo membro virtuale, usare la abstract parola chiave . Questa operazione viene eseguita indipendentemente dal fatto che si fornisca un'implementazione predefinita per tale metodo. Di conseguenza, una definizione completa di un metodo virtuale in una classe base segue questo modello:

abstract member [method-name] : [type]

default [self-identifier].[method-name] [argument-list] = [method-body]

E in una classe derivata, un override di questo metodo virtuale segue questo modello:

override [self-identifier].[method-name] [argument-list] = [method-body]

Se si omette l'implementazione predefinita nella classe base, la classe base diventa una classe astratta.

Nell'esempio di codice seguente viene illustrata la dichiarazione di un nuovo metodo function1 virtuale in una classe base e come eseguirne l'override in una classe derivata.

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

Costruttori ed ereditarietà

Il costruttore per la classe base deve essere chiamato nella classe derivata. Gli argomenti per il costruttore della classe base vengono visualizzati nell'elenco di argomenti nella inherit clausola . I valori utilizzati devono essere determinati dagli argomenti forniti al costruttore della classe derivata.

Il codice seguente mostra una classe di base e una classe derivata, in cui la classe derivata chiama il costruttore della classe base nella clausola 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

Nel caso di più costruttori, è possibile usare il codice seguente. La prima riga dei costruttori di classi derivate è la inherit clausola e i campi vengono visualizzati come campi espliciti dichiarati con la val parola chiave . Per altre informazioni, vedere Campi espliciti: parola val chiave.

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

Alternative all'ereditarietà

Nei casi in cui è necessaria una modifica secondaria di un tipo, è consigliabile usare un'espressione oggetto come alternativa all'ereditarietà. Nell'esempio seguente viene illustrato l'uso di un'espressione oggetto come alternativa alla creazione di un nuovo tipo derivato:

open System

let object1 =
    { new Object() with
        override this.ToString() = "This overrides object.ToString()" }

printfn "%s" (object1.ToString())

Per altre informazioni sulle espressioni oggetto, vedere Espressioni oggetto.

Quando si creano gerarchie di oggetti, è consigliabile usare un'unione discriminata anziché l'ereditarietà. Le unioni discriminate possono anche modellare diversi comportamenti di oggetti diversi che condividono un tipo complessivo comune. Una singola unione discriminata può spesso eliminare la necessità di una serie di classi derivate che sono variazioni secondarie l'una dell'altra. Per informazioni sulle unioni discriminate, vedere Unioni discriminate.

Vedi anche