Vous êtes sur la page 1sur 25

Classes et Objets en Ocaml.

Didier Rmy e 2001 - 2002

http://cristal.inria.fr/remy/mot/2/
http://www.enseignement.polytechnique.fr/profs/informatique/Didier.Remy/mot/2/

Cours 1. Objets 2. Classes 3. Hritage e 4. Typage Slide 1 5. Abrviations e 6. Sous-typage 7. Classes paramtres e e 8. Mthodes virtuelles e 9. Objets fonctionnels 10. Mthodes binaires e 1. Classes

Exercices

2. Les piles en style objet 3. Les cha nes en style objet 4. Variations sur la sauvegarde 5. Renommage

Avertissement
Ces notes introduisent informellement la couche objet du langage Caml. Le but nest pas ici dexpliquer ce que sont les objets ou les classes, mais dapprendre ` les utiliser dabord de faon intuitive dans des situations a c simples. Nous prsenterons galement des exemples plus avances dutilisation les e e e objets et des classes et nous expliquerons plus formellement le concept dobjet dans les cours suivants.

Slide 2

Objets et classes
Les classes (en rouge) sont des mod`les dobjets, extensibles (les `chent e e rouge reprsente lhritage). e e

Les objets (en bleu) sont des instances (`ches bleu) des classes, rigides. e Ce sont des valeurs qui peuvent tre arguments ou rsultats. e e

Slide 3

Les objets
Un objet est un enregistrement qui regroupe deux sortes de champs : Les variables dinstance, ventuellement mutables, forment ltat e e interne de lobjet ; ce sont des valeurs qui ne sont accessibles que par les mthodes. e Les mthodes sont des fonctions qui ont acc`s en plus de leurs e e arguments aux variables dinstance et ` lobjet lui-mme. a e Les objets sont construits ` partir des classes. a La seule opration possible sur les objets depuis lextrieur (i.e. en dehors e e de la classe qui le dnit) est lappel de mthode aussi appel envoi de e e e message. objet#mthode [ arguments ] e

Slide 4

Exemple : un compte en banque


Etat interne Solde du compte, Oprations rcentes, e e Dcouvert autoris, e e Mthodes e Consulter le solde, Dposer de largent, e Retirer de largent, Imprimer un relev. e

Slide 5 Exemple de messages envoys ` un objet compte c : e a c # dp^t (100.0) e o c # retrait (50.0) c # relev e

Les classes
Un mini langage pour abstraire les classes par rapport ` des arguments a (valeurs du langage de base ou objets) ou bien les appliquer ` des a arguments. Les dnitions de classes sont restreintes au toplevel. e Une classe totalement applique est un mod`le dobjet (une sorte de e e moule) dni par : e un ensemble de variables dinstances un ensemble de mthodes. e Au besoin, une classe est abstraite, explicitement, par rapport ` lobjet a (souvent mais pas obligatoirement appel self) qui sera dans le moule au e moment de lexcution des mthodes. e e On cre une instance du mod`le par new classe e e

Slide 6

Exemples
La classe vide class vide = object end;; let objet_vide = new vide;; let un_autre_objet_vide = new vide;; Egalit sur les objets e Slide 7 Dirents objets dune mme classe sont toujours dirents (chaque objet e e e port un champ invisible, son identit, dirent des autres) e e un_autre_objet_vide = objet_vide;;
: bool = false

objet_vide = objet_vide;;
: bool = true

class l`ve son_nom = object e e val nom : string = son_nom

val mutable moyenne = 0. val mutable nombre_de_notes = 0 method note x = let n = float nombre_de_notes in moyenne <- (x +. moyenne *. n) /. (n +. 1.); nombre_de_notes <- nombre_de_notes + 1; moyenne method bon_l`ve = moyenne > 14. e e end;; Slide 8

Exercice
Exercice 1 (Exemple (*)) Transformer un petit programme simple, monomorphe, sans classe en un programme avec une seule classe la plus englobante possible. Y a-t-il un intrt ` cette e e a Rponse e transformation ? Essayer de transformer une librairie de fonctions polymorphes, par exemple sur les listes. Quel est le probl`me rencontr ? e e Rponse e

Slide 9

Syntaxe des classes (simplie) e


Dnition de classe e class [ virtual ] [ [ Type-var* ] ] Nom [ Variable* ] = Classe Expression de classe Nom fun Variable* -> Classe Classe Expression* object [ ( Variable [ : Type ] ) ] Corps end Corps de classe [ Type* ] inherit Classe [ as Variable ] val [ mutable ] Variable = Expression method [ virtual ] [ private ] Variable = Expression initializer Expression Nouvelles expressions du langage de base Variable <- Expression Expression # Variable new Classe

Slide 10

Slide 11

e class compte = Hritage : compte bancaire object val mutable solde = 0.0 method solde = solde method dp^t x = solde <- solde +. x e o method retrait x = if x <= solde then (solde <- solde -. x; x) else 0.0 end;; let c = new compte in c # dp^t 100.0; c # retrait 50.0;; e o
Envoi de message ` soi-mme. a e class compte_avec_intr^ts = e e object (self) inherit compte method intr^ts = self # dp^t (0.03 *. self # solde) e e e o end;;

Mthode prive e e
Il peut tre utile de ne pas donner la mthode intr^ts ` lutilisateur, e e e e a mais seulement de la rendre visible dans les sous-classes en vue dune utilisation ultrieure. e On en fait une mthode prive : e e class compte_avec_intr^ts = e e object (self) inherit compte method private intr^ts = e e self # dp^t (0.03 *. self # solde) e o end;; Les mthodes prives ne sont pas accessibles de lextrieur e e e (new compte_avec_intr^ts) # intr^ts;; e e e e This expression has type compte_avec_intr^ts e e It has no method intr^ts e e

Slide 12

Liaison tardive
Un appel rcursif ` une mthode prend en compte sa rednition e a e e ultrieure ; cest le mcanisme de la liaison tardive. e e Par exemple si on corrige le comportement de la mthode dpt pour e e o viter une usage abusif : e class bon_compte = object inherit compte_avec_intr^ts e e method dp^t x = if x > 0.0 then solde <- solde +. x e o end;; La mthode intr^ts appellera la nouvelle dnition de la mthode e e e e e dp^t. e o

Slide 13

Ranement dune mthode e


Lors de lhritage, on peut lier la vue de lobjet dans la classe parente e pour appeler les anciennes mthodes. e Ainsi, on aurait pu dnir : e class bon_compte = object inherit compte_avec_intr^ts as super e e method dp^t x = e o if x > 0.0 then super # dp^t x e o else raise (Invalid_argument "dp^t") e o end;; Ce qui noblige pas ` conna limplmentation actuelle de la mthode a tre e e dp^t e o

Slide 14

Compte avec relev e


Mlange des aspects prcdents dans un compte avec relev e e e e type opration = Dp^t of float | Retrait of float e e o class compte_avec_relev = e object (self) inherit bon_compte as super val mutable registre = [] method private trace x = registre <- x::registre method dp^t x = e o self#trace (Dp^t x); super # dp^t x e o e o method retrait x = self#trace (Retrait x); super # retrait x method relev = List.rev registre e end;;

Slide 15

Initialisation des objets


On peut abstraire une classe par rapport ` des valeurs initiales. a Le mieux aurait t de le prvoir d`s le dpart. On peut aussi utiliser la ee e e e clause initializer pour rattraper le coup. Paramtrisation a priori e class compte x = object val mutable solde = x method ... ... end Paramtrisation a posteriori e class promotion x = object (self) inherit compte_avec_relev e initializer solde <- x end;;

Slide 16

Les clauses initializer sont excutes immdiatement apr`s la cration e e e e e de lobjet, dans lordre de dnition. Elles ont acc`s aux variables e e dinstance et ` self. a Plus souvent utilises pour assurer des invariants. e

Clause dinitialisation
On peut aussi eectuer un dpt automatique apr`s la cration de lobjet e o e e (ce qui correspond ` lide de promotion). a e class promotion x = object (self) inherit compte_avec_relev e initializer self # dp^t x e o end;; Cette version eectue linitialisation comme un dpt, ce qui empche e o e automatiquement linitialisation avec une valeur ngative. e let ccp = new promotion 100.0 in ignore (ccp # retrait 50.0); ccp # relev;; e
: opration list = [Dpt 100; Retrait 50] e e o

Slide 17

Types des objets


Les types des objets sont de petits enregistrements de types : Le type dun compte bancaire : type compte_bancaire = < solde : float; dp^t : float -> unit; e o retrait : float -> float; relev : opration list >;; e e (new promotion 50.0 : compte_bancaire);; (new compte : compte_bancaire);; Only the second object type has a method relev e Le type compte_bancaire est dit ferm (enti`rement spci) e e e e

Slide 18

Types des objets ouverts


Le type dun objet peut tre partiellement spci. e e e let fermeture c = c # retrait (c # solde);;
val fermeture : < retrait : a -> b; solde : a; .. > -> b = <fun>

Slide 19

Cette fonction, polymorphe, peut sappliquer ` toutes sortes de comptes. a Les .. se comporte comme une variable de type anonyme. fermeture (new compte);; fermeture (new promotion 100.0);; Le partage est exprim et conserv par la construction as e e let dp^t c x = if x > 100.0 then c # dp^t x; c;; e o e o
val dpt : (< dpt : oat -> unit; .. > as a) -> oat -> a = <fun> e o e o

(dp^t (new compte), dp^t (new compte_avec_relev));; e o e o e


: (oat -> compte) (oat -> compte avec relev) = <fun>, <fun> e

Types des classes


Les types des classes sont des petites spcications qui dcrivent la e e structure des classes. Dans les classes, le type de self est toujours ouvert (partiellement spci). Il est compatible avec lensemble des mthodes couramment e e e dnies. e Slide 20

Syntaxe des types des classes


Type-de-dnition-de-classe e class [ virtual ] [ [ Type-var* ] ] Nom [ Type* ] : T Dnition-de-type-de-classe e class type [ virtual ] [ [ Type-var* ] ] Nom [ Type* ] = T T (Type de classe) Nom Type -> T object [ ( Type ) ] Type-du-corps end Type-du-corps val [ mutable ] Variable : Type method [ virtual ] [ private ] Variable : Type Nouvelles expressions de type < variable : Type [ ; variable : Type ] * [ ; .. ] > ( Type as Type-var )

Slide 21

Exemple
Le type (infr) des classes avec relev : ee e class compte_avec_relev : e object val mutable registre : opration list e val mutable solde : float method dp^t : float -> unit e o method private intr^ts : unit e e method relev : opration list e e method retrait : float -> float method solde : float method private trace : opration -> unit e end

Slide 22

Abrviations automatiques e
Les dnitions de classes (et de types de classes) crent automatiquement e e des abrviations de types e type compte_avec_relev = e < dp^t : float -> unit; relev : opration list; e o e e retrait : float -> float; solde : float > Slide 23 type #compte_avec_relev = e < dp^t : float -> unit; relev : opration list; e o e e retrait : float -> float; solde : float; .. > Le premier est une instance du second. En fait tout objet dune sous-classe de compte_avec_relev est une instance du second. e fun x -> ( (x : compte_avec_relev) : #compte);; e

Sous-typage sur les objets


Les types compte_avec_relev et compte sont incompatibles. e fun x -> ( (x : compte_avec_relev) : compte);; e Mais on peut explicitement coercer lun vers lautre : fun x -> (x : compte_avec_relev :> compte);; e Il existe un raccourci, moins puissant mais souvent susant (utiliser la version longue lorsque le raccourci ne sapplique pas) fun x -> (x :> compte);; Par exemple, pour mettre les comptes avec ou sans relev dans une mme e e collection : [ (new compte :> compte); (new compte_avec_relev :> compte) ];; e
: compte list = [<obj>; <obj>]

Slide 24

R`gle de sous-typage (approximation) e


Un type dobjet A est un sous-type dun type dobjet B si A et B sont gaux ou bien tous deux ferms et tels que : e e chaque mthode de A est une mthode de B ; e e son type dans A est un sous-type de son type dans B (sous-typage en profondeur) ; Le type de DA IA dune fonction est sous-type de DB IB si IA est sous-type de IB on peut agrandir lImage DB est sous-type de DA on peut rtrcir son Domaine e e e En particulier, si A et B contiennent une mme mthode binaire, e.g. : e A = (< m : a -> unit; ... > as a) B = (< m : b -> unit; ... > as b) e a alors A est sous-type de B seulement sil est gal ` B. En eet, pour que A soit sous-type de B la contavariance sur la mthode m ne impose que e e a B soit aussi sous-type de A, et la seule solution est que A soit gal ` B. (On vrie facilement la relation de sous-typage est antisymmtrique.) e e

Slide 25

Que peut-on cacher dans une classe ?


Les variables dinstance et les mthodes prives peuvent tre caches en e e e e donnant ` la classe une contrainte de type. a class foo : object method m : int end = object (self) val foo = 2 method private bar = foo * foo method m = self # bar * self # bar end;; Le mme eet peut tre produit par une contrainte de signature e e module Truc : sig class inutile : object end end = struct class inutile = object val foo = 2 end end;;

Slide 26

Classes paramtres e e
Une mappe est une table dassociation. class type [a, b] mappe = object method trouve : a -> b method ajoute : a -> b -> unit end;; Slide 27 Une implmentation simple et raisonnable pour de petites mappes avec e des listes : class [a, b] petite_mappe : [a, b] mappe = object val mutable table = [] method trouve cl = List.assoc cl table e e method ajoute cl valeur = table <- (cl, valeur) :: table e e end;;

Classes paramtres e e
Une implmentation plus ecace pour les mappes de grande taille avec e une table de hache. Pour rsoudre les conits, les lments de la table de e ee hache sont eux mmes des petites mappes. e class [a, b] grande_mappe taille : [a, b] mappe = object (self) val table = Array.init taille (fun i -> new petite_mappe) method private hash cl = e e (Hashtbl.hash cl) mod (Array.length table) method trouve cl = table.(self#hash cl) # trouve cl e e e method ajoute cl = table.(self#hash cl) # ajoute cl e e e end;; Une version plus ecace pourrait automatiquement retailler la table de hache lorsque les petites mappes deviennent trop grandes (` condition de a leur ajouter une mthode taille). e

Slide 28

Exercice
Exercice 2 (Piles (*)) Ecrire une classe des piles (dentiers) Gnraliser en une classe paramtrique des piles. e e e Rponse e Notez les dirences avec les piles comme module. e

Slide 29

Classes et mthodes virtuelles e


Une mthode est virtuelle lorsquelle est utilise mais pas dnie. La e e e classe est alors elle mme virtuelle : on peut en driver des sous-classes, e e mais pas en crer des instances. e Les mthodes virtuelles peuvent tre utilises pour dnir un e e e e comportement commun aux sous-classes utilisant des caractristiques pas e encore dnies des sous-classes. e Une classe virtuelle doit tre indique comme telle. (ce qui vite quune e e e mthode mal orthographie deviennent accidentellement virtuelle...) e e Exemple Une classe dnit des r`gles gnrales, un protocole, etc. Une e e e e ou plusieurs sous classes implmentent une stratgie, un comportement e e plus prcis. e

Slide 30

Exemple : jeu et stratgies e


Les r`gles du jeu sont partages e e class virtual joueur nom = object (self : a)

method virtual coup : int


Slide 31 method vrifie n = 1 + (n-1) mod 2 e method joue_avec (partenaire : a) jeu = if (jeu = 0) then (nom : string) else let suivant = jeu - (self # vrifie (self # coup)) in e partenaire # joue_avec self suivant end;;

Exemple : jeu et stratgies e


Deux stratgies indpendantes e e class petit nom = object inherit joueur nom method coup = 1 end;; class hasard nom = object inherit joueur nom method coup = 1 + Random.int 2 end;;

Slide 32

La partie (new hasard "Pierre") # joue_avec (new petit "Jacques") 26;;

Les modicateurs de champs


Les modicateurs de champs sont visibles et hrits dans les sous-classes, e e a ` moins quils ne soient masqus par le typage. e val mutable Ce modicateur peut tre ajout tardivement et masqu par le typage. e e e Slide 33 method private Annotation ` placer d`s lorigine, hrite. La mthode, invisible dans a e e e e lobjet, peut tre cache dans la classe par le typage. e e class virtual, method virtual Annotation obligatoire pour une mthode utilise mais non dnie et e e e pour une classe comprenant une telle mthode. Proprit hrite qui e ee e e dispara apr`s dnition de la mthode. t e e e

Objets dans le style fonctionnel


On peut retourner une copie supercielle dun objet quelconque en utilisant la fonction de librairie : Oo.copy : (< .. > as a) -> a Dans une dnition de classe, on peut aussi retourner une copie de self e avec certains champs ventuellement modis par la construction : e e Slide 34 o` les champs u
1

{ a `
k

= e1 ; . . .

= ek }

sont un sous-ensemble des variables dinstances.

Exemple : les mappes fonctionnelles


La mthode ajoute doit retourner une nouvelle mappe, sans modier e lancienne.
class type [a, b] mappe_fonctionnelle = object (mytype) method trouve : a -> b method ajoute : a -> b -> mytype end;;

Slide 35

Des petites mappes peuvent tre reprsentes par des listes : e e e class [a, b] petite_mappe : [a, b] mappe_fonctionnelle = object val mutable table = [] method trouve cl = List.assoc cl table e e method ajoute cl valeur = e {< table = (cl, valeur) :: table >} e end;;

Hritage multiple e
Une classe en librairie... class sauvegarde = object (self : mytype) val mutable copie = None method sauve = copie <- Some {< >} method rcup`re = e e match copie with (Some x) -> x | _ -> raise Not_found end;; Note : ici on peut remplacer {< >} par (Oo.copy self). e e Les fonctionnalits de la classe sauvegarde peuvent tre ajoutes a e a posteriori ` (presque) nimporte quelle autre classe, e.g. : class compte_protg = e e object inherit compte inherit sauvegarde end;;

Slide 36

Exercices
Exercice 3 (Sauvegarde) Les fonctionnalits de la classe sauvegarde e peuvent tre ajoutes ` presque nimporte quelle autre classe. Pourquoi e e a presque ? Rponse e La classe sauvergarde permet cha en fait les versions entre elles. On ne peut donc rcuprer une version de deuxi`me gnration entre rcuprant e e e e e e e la sauvegarde de la sauvegarde. Ecrire une variante de la classe sauvegarde qui ne conserve quune seule copie. Quel est lintrt de cette modication (si une seule copie est e e Rponse e ncessaire) ? e Ecrire une variante fonctionnelle fsauvegarde de la classe sauvegarde : la mthode rcup`re retourne un objet qui est une copie de self dans e e e laquelle le champ original pointer vers la version originale. Il faut continuer avec la copie pour pouvoir plus tard rcuprer la version e e Rponse e originale.

Slide 37

On reprend la version qui conserve les sauvegardes intermdiaires. e Raner la version imprative de la sauvergarde en profondeur en ajoutant e une mthode balai qui conserve les sauvegardes de faon logarithmique e c Rponse e (i.e. ne conserve que les versions dge 20 , 21 , ... 2n ). a

Slide 38

Mthodes binaires e
Ce sont des mthodes qui prennent parmi leurs arguments au moins un e objet du mme type que self. e Les vraies class binaire = object (self) method choisir x = if Random.int 1 = 0 then x else self end;; class binaire : object (a) method choisir : a -> a end Le type dun objet avec une mthode binaire visible na que lui-mme e e pour sous-type. En corollaire, pour cacher certaines mthodes par e sous-typage, il faut aussi cacher toutes ses mthodes binaires. e Les fausses La contrainte de type ` lorigine de la mthode binaire peut a e tre relche, en gnrale en rendant la classe paramtrique en le type de e a e e e e cet argument.

Slide 39

Mthodes binaires et classes paramtres e e e


class toile = e object (self : a) val mutable pos = 0 method pos = pos method eq (x : a) = (x#pos = self#pos) end;;
class toile : object (a) e val mutable pos : int method eq : a -> bool method pos : int end

Slide 40

class [a] toile = e object (self) val mutable pos = 0 method pos = pos method eq (x : a) = (x#pos = self#pos) end;;
class [ a] toile : e object constraint a = < pos:int; .. > val mutable pos : int method eq : a -> bool method pos : int end

La mthode eq est-elle binaire ? e

OUI

NON

Exercices
Exercice 4 (Mthodes binaires (**)) Crer une classe string avec e e les fonctionnalits essentielles des cha e nes. nes de caract`res. e Ajouter une mthode concat aux cha e Quel est le probl`me ventuel ? e e Slide 41 Rponse e

Exercices (suite)
Exercice 5 (Renommage (***)) En considrant que la monnaie par e e o dfaut est le franc, tendre la classe compte pour fournir des dpts et e e des retraits en euros, les conversions tant explicites. (Ici, on ne demande e pas de cacher la reprsentation de la monnaie par lutilisation de type e abstrait ; on pourra donc utiliser des oat ` la fois pour reprsenter les a e dollars et les francs. Voir lexercice sur les taux de changes.) Slide 42 Reprendre le mme exercice, mais en dnissant dabord une classe e e euro_compte puis une ensuite classe compte_mixte par hritage multiple. e Quel est le probl`me ventuel ? e e Rponse e

Solutions des exercices

Exercice 1, page 9
Il ny a pas dintrt a priori, sauf situation tr`s particuli`re. Cette transformation vient ee e e surtout des langages tout objets qui nont pas de fonctions mais seuleument des mthodes. e En Ocaml, les fonctions sont faciles ` dnir et ` manipiler. Lorsque cette approche sut, a e a elle est plus lg`re que le style ` objets et donc prfrable. e e a ee Exercice 1 (continued) Lorsque des fonctions polymorphes sont mises dans une classes ont voudrait en faire des mthodes polymorphes. Mais ce nest pas possibles car les objets ne sont jamais polymorphes e (comme des rfrences, ils contiennent des champs mutables), et leurs mthodes non plus. ee e Au mieux on pourrait dnir une classe paramtrique (par exemple des oprations sur e e e les listes), mais ils faudra spcialiser celles-ci compltement ` la cration dun objet. Cest e e a e une limitation forte ` lusage des classes pour regrouper des fonctions de librairie. a

Exercice 2, page 29
On ne donne que la solution pour des classes paramtriques reprsentes par des listes. e e e exception Vide;; class [a] pile = object val mutable p : a list = [] method ajouter x = p <- x :: p

method retirer = match p with | [] -> raise Vide | x::t -> p <- t; x end;;

Exercice 3, page 37
Les noms de mthodes cette autre classe ne doivent pas tre en conit avec ceux de la e e classe sauvegarde. Exercice 3 (continued) Il sut lorsquon prend une copie de mettre le champ copie ` None : a class une_sauvegarde = object (self : mytype) inherit sauvegarde method sauve = copie <- Some {< copie = None >} end;; Si une seule copie est ncessaire, la version ci-dessus lib`re les anciennces versions qui peuvent e e tre rcupres par le GC. Dans la version prcdentes toutes les versions intermdiaires e e ee e e e restaient vivantes aussi longtemps que la version de travail. Exercice 3 (continued) class fsauvegarde = object (self) val original = None method copie = {< original = Some self >} method rcup`re = e e match original with None -> self | Some x -> x end;; Exercice 3 (continued) La mthode balai eace rcursivement et physiquement certaines copie en les faisant e e pointer vers la copie prcedente. e class sauvegarde_autogre = e e object (self : mytype) inherit sauvegarde method private coup_de_balai p q = try let q = if p = q then 2 * q else q in let la_sauvegarde = self # rcup`re # coup_de_balai (succ p) q in e e copie <- la_sauvegarde; if p = q then Some self else la_sauvegarde with Not_found -> None method balai = ignore (self#coup_de_balai 1 1) end;; Remarquer limportance de faire une mthode auxilliaire de coup_de_balai. Une fonction e ne conviendrait pas, car coup_de_balai utilise la variable dinstance copie.

Exercice 4, page 41
La mthode concat pose probl`me parce que cest une mthode binaire. En fait, cest e e e une pseudo mthode binaire. En eet, si on naturellement : e

class ostring s = object (self) val s = s method repr = s method concat t = {< s = s ^ t # repr >} end;; e e alors largument t nest pas ncessairement du type de self, mais doit seulement possder une mthode repr du bon type. Cela rend la class paramtrique (do` le message derreur). e e u Une solution est donc : class [a] ostring s = object (self) val s = s method repr = s method concat (t:a) = {< s = s ^ t # repr >} end;; Une autre solution, sans doute meilleurs en pratique, et de contraindre le type a de t a tre e le mme que le type de self (la classe nest plus paramtrique) e e class ostring s = object (self : a) val s = s method repr = s method concat (t:a) = {< s = s ^ t # repr >} end;; ae Attention ! on pourrait aussi contraindre t ` tre du type de la classe string class ostring s = object (self : a) val s = s method repr = s method concat (t : ostring) = {< s = s ^ t # repr >} end;; Cette solution nest pas bonne car dans une sous-classe enrichie ostring_plus, la mthode e concat ne se comportera pas comme attendu : elle prendra et un argument du type ostring et non pas du type ostring_plus.

Exercice 5, page 42
Le probl`me ventuel est le conit de nom, si par exemple, la classe euro_compte utiliser e e les mmes mthodes dp^t et retrait que la classe compte. e e e o Malheureusement, il nest pas possible (pour linstant, en Ocaml) de renommer les mthodes. e Le choix des noms est important en style objet, car la programmation par envoi de messages attache un smantique implicite ` chaque message et les noms sont bien plus e a que des conventions syntaxiques. Par exemple, un object imprimable aura naturellement une mthode print, sinon il ne pourra pas tre imprim par dautres classes dnies en e e e e librairie. La solution la plus simple consiste ` prvoir ce conit et choisir des noms dirents pour a e e chacune des mthodes. e class euro_compte = object val sole_en_euro = ... method dp^t_en_euro = ... e o end Une autre solution, plus modulaire, sinon plus lgante, permet toutefois de partager le ee compte en euro et en francs. Mais il faut pour cela prvoir le conit, et utiliser un motif en e peigne (cf introduction) avec une classe gnratrice, o` les noms sont privs, et des classes e e u e drives o` les noms sont gs. (On choisi une version simpli, mais on imaginera une e e u e e version rane de la classe ou le corps de la mthode dp^t est susamment gros pour e e e o justier le partage). class compte = object val mutable solde = 0. method private dp^t x = solde <- solde +. x; solde e o end;;

Pour la classe en franc, on choisit des nom prcis e class type compte_franais = object c method dp^t_en_franc : float -> float e o end class compte_en_franc : compte_franais = object (self) c inherit compte method dp^t_en_franc = self#dp^t e o e o end;; Pour de faon similaire en vitant les conits de noms : c e class type compte_europen = object e method dp^t_en_euro : float -> float e o end class compte_en_euro : compte_europen = object (self) e inherit compte method dp^t_en_euro = self#dp^t e o e o end;; On peut alors mlanger les deux comptes : e class compte_mixte = object inherit compte_en_franc inherit compte_en_euro end;; On vrie que la class compte_mixte comporte bien deux variables dinstances soldes caches e e distinctes : il ny a pas doverride entre les champs (variables ou mthodes) cachs. (Dans e e cette version simpli du compte, on eectue un dpt vide pour lire la valeur du compte) : e e o let cm = new compte_mixte;; let soldes() = (cm # dp^t_en_franc 0., cm # dp^t_en_euro 0.);; e o e o soldes();;
: oat oat = 3.000000, 4.000000

cm # dp^t_en_franc 1.;; e o
: oat = 4.000000

soldes();;
: oat oat = 4.000000, 4.000000

cm # dp^t_en_euro 2.;; e o
: oat = 6.000000

soldes();;
: oat oat = 4.000000, 6.000000

NOTE : On a ainsi rsolu le probl`me de faon modulaire (partage du code), mais au e e c pris dun motif en peigne, quil a fallu concevoir a priori.