Herencia (F#)
La herencia se utiliza para modelar la relación de identidad o la derivación de subtipos en la programación orientada a objetos.
Especificar relaciones de herencia
Las relaciones de herencia se especifican mediante la palabra clave inherit en una declaración de clase. El formato sintáctico básico se muestra en el ejemplo siguiente.
type MyDerived(...) =
inherit MyBase(...)
Una clase puede tener como mucho una clase base directa. Si no se especifica una clase base mediante la palabra clave inherit, la clase heredará implícitamente de Object.
Miembros heredados
Si una clase hereda de otra clase, los métodos y miembros de la clase base estarán disponibles para los usuarios de la clase derivada como si fuesen miembros directos de la clase derivada.
Todos los enlaces let y parámetros de constructor son privados para una clase y, por consiguiente, no son accesibles desde las clases derivadas.
La palabra clave base está disponible en las clases derivadas y hace referencia a la instancia de la clase base. Se utiliza como el identificador de la instancia actual.
Métodos virtuales y reemplazos
Los métodos (y propiedades) virtuales funcionan en F# de manera un tanto diferente que en los otros lenguajes .NET. Para declarar un nuevo miembro virtual, se usa la palabra clave abstract. independientemente de si se proporciona una implementación predeterminada de ese método. Por consiguiente, una definición completa de un método virtual en una clase base sigue este modelo:
abstract member method-name : type
default self-identifier.method-name argument-list = method-body
En una clase derivada, un reemplazo de este método virtual sigue este modelo:
override self-identifier.method-name argument-list = method-body
Si se omite la implementación predeterminada en la clase base, esta pasa a ser una clase abstracta.
En el ejemplo de código siguiente se muestra la declaración de un nuevo método virtual function1 en una clase base y cómo reemplazarlo en una clase derivada.
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
Constructores y herencia
El constructor de la clase base debe invocarse en la clase derivada. Los argumentos del constructor de la clase base aparecen en la lista de argumentos de la cláusula inherit. Los valores usados deben determinarse a partir de los argumentos proporcionados al constructor de la clase derivada.
En el código siguiente se muestran una clase base y una clase derivada. La clase derivada llama al constructor de la clase base en la cláusula 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
En caso de haber varios constructores, se puede usar el código siguiente. La primera línea de los constructores de clases derivadas es la cláusula inherit y los campos aparecen como campos explícitos que se declaran con la palabra clave val. Para obtener más información, vea Campos explícitos: palabra clave 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")
Alternativas a la herencia
En los casos en los que se requiere una pequeña modificación de un tipo, considere la posibilidad de usar una expresión de objeto como alternativa a la herencia. En el ejemplo siguiente se muestra el uso de una expresión de objeto como alternativa a la creación de un nuevo tipo derivado:
open System
let object1 = { new Object() with
override this.ToString() = "This overrides object.ToString()"
}
printfn "%s" (object1.ToString())
Para obtener más información sobre las expresiones de objeto, vea Expresiones de objeto (F#).
Al crear jerarquías de objetos, considere la posibilidad de usar una unión discriminada en lugar de la herencia. Las uniones discriminadas también permiten modelar un comportamiento variado de diferentes objetos que comparten un tipo global común. A menudo, una sola unión discriminada puede eliminar la necesidad de crear varias clases derivadas que son pequeñas variaciones unas de otras. Para obtener información sobre las uniones discriminadas, vea Uniones discriminadas (F#).