Les traitements sont décrits par des fonctions et des procédures que l'on appelle des méthodes.
Comment créer plusieurs comptes? Une solution consiste à réécrire le code qui définit un compte. C'est ce que permettent les langages modulaires sans généricité. Dans les langages objets, les objets vont pouvoir être dynamiquement cr'eés à partir de la notion de classe.
De plus, dans beaucoup de langages objets, il n'y a pas de possibilités de créer directement un objet. Il faut d'abord définir une classe.
Par exemple, les comptes bancaires décrits ci-dessus peuvent s'écrire dans la syntaxe java:
class Compte{ int solde = 0; void depot (int n){ solde = solde + n; } void retrait (int n){ solde = solde - n; } void print (){ System.out.println(solde); } }Un compte peut être créé à partir de cette classe par la construction prédéfinie:
new Compte();On peut nommer l'objet créé en utilisant une variable déclarée préalablement.
Compte martin; martin = new Compte();Dans cette construction, new Compte() est l'appel à un opérateur appelé constructeur qui crée les objets de la classe Compte. Nous reviendrons plus tard sur la définition, l'utilisation, la sémantique, des constructeurs.
On dit qu'un objet créé à partir d'une classe est une instance de cette classe: martin est une instance de Compte.
Les méthodes sont appelées sur un objet et vont modifier son état. Par exemple:
martin.depot(500); martin.retrait(100); martin.print();
Exemple: on va définir les comptes rémunérés. Il faut ajouter le taux d'intérêt et le calcul des intérêts.
class CompteRemunere extends Compte{ int taux = 5; // exprime en % void interet(){ solde = solde + ((solde * taux)/100); } } ... CompteRemunere dupont = new CompteRemunere(); dupont.depot(1000); dupont.interet(); dupont.print(); ...Un objet créé à partir de la classe CompteRemunere possède aussi la variable solde et les méthodes de la classe Compte.
Autre exemple:
class CompteSecurise extends Compte{ void retrait(int n){ if (solde >= n) solde = solde - n; else{ System.out.print("provision insuffisante :"); print(); }; } } ... CompteSecurise durand = new CompteSecurise(); durand.depot(200); durand.retrait(300); ...Les classes CompteRemunere et CompteSecurise héritent de la classe Compte.
Lorsqu'une classe peut hériter de plusieurs super-classes, on parle d'héritage multiple. C'est la cas pour les langages C++, Eiffel, Ocaml. La hiérarchie forme un treillis.
Dans notre exemple, la relation d'héritage est:
Object | | Compte /\ / \ CompteRemunere CompteSecuriseEn java, la hiérarchie a toujours pour racine la classe prédéfinie Object qui fournit un certain nombre de méthodes et constructeurs.
Limitations de la structure de bloc d'un langage procédural: Prenons l'exemple suivant:
declare cptF: integer; cptG: integer; function F () ; ... cptF:= cptF +1; end F; function G () ; ... cptG:= cptG +1; end F; begin cptF:=0; cptG:=0; endL'initialisation des compteurs cptF et cptG ne peut être faite que dans le programme principal. Ces deux compteurs doivent donc être des variables globales et sont donc accessibles par tous les objets du programme.
Dans les langages objets, ce problème ne se pose plus. Par exemple, la variable solde est locale à chaque objet.
En java, il est possible de préciser la visibilité des différents composants d'une classe (variables et méthodes) avec des déclarations appropriées:
En Ocaml, les variables d'instances sont toujours invisibles.
En JAVA, si nous souhaitons rendre inaccessible le solde d'un compte, nous écrivons:
class Compte{ protected int solde = 0; void depot (int n){ solde = solde + n; } void retrait (int n){ solde = solde - n; } void print (){ System.out.println(solde); } }Nous utilisons protected et non private parce que les méthodes de CompteRemunere et de CompteSecurise utilisent solde. Dans le CompteRemunere, le taux peut être déclaré private, ce qui le rend inaccessible hors de la classe.
Soit l'exemple:
class Banque { public Compte ouverture(){ Compte C; String reponse; DataInputStream In = new DataInputStream(System.in); System.out.println("Voulez-vous un compte securise?"); reponse=In.readLine(); if (reponse == "oui") C = new CompteSecurise(); else C = new Compte(); return C; } ... Compte Nguyen = ouverture(); Nguyen.depot(300); Nguyen.retrait(400); Nguyen.print(); ... }La classe de l'objet Nguyen dépend d'une valeur entrée par l'utilisateur, qui n'est donc connue qu'à l'exécution. La méthode retrait n'est pas la même selon la classe (Compte ou CompteSecurise). Son code ne pourra être déterminé que lors de l'exécution. La liaison du nom au code est donc dynamique.
On dit qu'on a une liaison retardée. Par contre, la méthode print est la même dans les deux classes. La liaison nom-code est déterminée statiquement à la compilation.
La liaison retardée est parfois appelée polymorphisme. Nous préférons le terme liaison retardée.
Classes spaghetti: difficulté de lecture et nécessité d'outils adaptés.
Exemple dans la syntaxe Simula:
Pile class PileUndo begin ref(Element) last; Element procedure Pop begin last:-s(haut); end procedure Undo; begin Push(last) end end PileUndoElement est le nom d'une classe et last est une variable dont la valeur est un element d'Element ou d'une sous classe d'Element.
Simula est un langage typé.
class A ... A class B... ... ref(A)a; ref(B)b; ... a:-b; -- correct statiquement ... b=:-a;--peut etre correct dynamiquement
class A ... class B: public A ... ... A*a; B*b; ... a=b; ... b=(B*)a;-- mais b=a est incorrect