Le code pre-existant n'est pas toujours adaptée à tous les contextes de re-utilisation. Il arrive alors que l'on mélange héritage et re-définition des méthodes pour décrire, en particulier, du code plus spécialisé dans une sous-classe. Une nouvelle version de la sous-classe compteremunere re-définit la méthode d'affichage pour signaler la part des interêts dans le solde du compte.
class compteremunere s_init = object inherit compte s_init val taux = 5 (* Donne en % *) val mutable interets = 0 method ajout_interets = begin interets <- (solde*taux)/100; solde <- solde + interets end method affiche_solde = begin print_string"Votre solde est: "; print_int solde; print_newline (); print_string" dont la part d'interets est: "; print_int interets end end;;
L'exemple suivant montre le nouveau comportément de l'affichage:
# let compterem1 = new compteremunere 200;; val compterem1 : compteremunere = <obj> # compterem1#ajout_interets;; - : unit = () # compterem1#affiche_solde;; Votre solde est: 210 dont la part d'interets est: 10 - : unit = ()
En Ocaml, il existe une contrainte (que nous justifierons plus tard) à la re-définition d'une méthode pendant l'héritage: le type de la méthode dérivée doit être égal ou plus spécialisé (du point de vue du polymorphisme3) que celui de la méthode parente. Intuitivement, cette contrainte n'est pas surprenante: la spécialisation (éventuelle) du type et du comportément d'une méthode est cohérente avec la notion même de spécialisation d'une classe par héritage. Dans notre exemple, le type de affiche_solde reste inchangé, et de ce fait, la re-définition de la méthode dans la nouvelle classe est validée par le typeur:
class compteremunere : int -> object val mutable interets : int val mutable solde : int val taux : int method affiche_solde : unit method ajout_interets : unit method donne_solde : int method depot : int -> unit method retrait : int -> unit end