Héritage
L’héritage est utilisé pour modéliser la relation "is-a", (est-un), ou sous-typage, en programmation orientée objet.
Spécification des relations d’héritage
Vous spécifiez les relations d’héritage en utilisant le mot clé inherit
dans une déclaration de classe. La forme syntaxique de base est illustrée dans l’exemple suivant.
type MyDerived(...) =
inherit MyBase(...)
Une classe peut avoir au maximum une classe de base directe. Si vous ne spécifiez pas de classe de base à l’aide du mot clé inherit
, la classe hérite implicitement de System.Object
.
Membres hérités
Si une classe hérite d’une autre classe, les méthodes et les membres de la classe de base sont disponibles pour les utilisateurs de la classe dérivée, comme s’il s’agissait de membres directs de la classe dérivée.
Les liaisons let et les paramètres de constructeur sont privés pour une classe. Ils ne sont donc pas accessibles à partir de classes dérivées.
Le mot clé base
est disponible dans les classes dérivées et fait référence à l’instance de la classe de base. Il est utilisé en tant qu’auto-identificateur.
Méthodes virtuelles et substitutions
Les méthodes (et propriétés) virtuelles fonctionnent un peu différemment en F# par rapport aux autres langages .NET. Pour déclarer un nouveau membre virtuel, vous utilisez le mot clé abstract
. Vous effectuez cette opération, que vous fournissiez ou non une implémentation par défaut pour cette méthode. Ainsi, une définition complète d’une méthode virtuelle dans une classe de base suit ce modèle :
abstract member [method-name] : [type]
default [self-identifier].[method-name] [argument-list] = [method-body]
Dans une classe dérivée, une substitution de cette méthode virtuelle suit ce modèle :
override [self-identifier].[method-name] [argument-list] = [method-body]
Si vous omettez l’implémentation par défaut dans la classe de base, la classe de base devient une classe abstraite.
L’exemple de code suivant illustre la déclaration d’une nouvelle méthode virtuelle function1
dans une classe de base, et sa substitution dans une classe dérivée.
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
Constructeurs et héritage
Le constructeur de la classe de base doit être appelé dans la classe dérivée. Les arguments du constructeur de classe de base apparaissent dans la liste d’arguments de la clause inherit
. Les valeurs utilisées doivent être déterminées à partir des arguments fournis au constructeur de classe dérivée.
Le code suivant montre une classe de base et une classe dérivée, où la classe dérivée appelle le constructeur de classe de base dans la clause 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
Dans le cas de figure où il existe plusieurs constructeurs, le code suivant peut être utilisé. La première ligne des constructeurs de classe dérivée est la clause inherit
. Les champs apparaissent sous forme de champs explicites déclarés avec le mot clé val
. Pour plus d’informations, consultez Champs explicites : mot clé 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")
Alternatives à l’héritage
Dans les cas où une modification mineure d’un type est nécessaire, utilisez une expression d’objet à la place de l’héritage. L’exemple suivant illustre l’utilisation d’une expression d’objet à la place de la création d’un type dérivé :
open System
let object1 =
{ new Object() with
override this.ToString() = "This overrides object.ToString()" }
printfn "%s" (object1.ToString())
Pour plus d’informations sur les expressions d’objet, consultez Expressions d’objet.
Quand vous créez des hiérarchies d’objets, utilisez une union discriminée à la place de l’héritage. Les unions discriminées peuvent également modéliser le comportement varié de différents objets qui partagent un type global commun. Une seule union discriminée permet souvent d’éliminer le recours à un certain nombre de classes dérivées qui sont des variantes mineures les unes des autres. Pour d’informations sur les unions discriminées, consultez Unions discriminées.