next up previous contents index
Next: Liaison tardive Up: Héritage Previous: Héritage

     
Héritage de types abstraits

Rappelons qu'une méthode abstraite est une méthode déclarée abstract et dont le corps est remplacé par un << ; >>. Une classe abstraite est une classe qui a au moins une méthode abstraite (éventuellement héritée d'une classe parente abstraite) ; une telle classe doit être déclarée abstract. Les classes abstraites sont donc des classes partiellement implémentées, puisqu'elles peuvent aussi avoir des champs et des méthodes non-abstraites. Une classe abstraite ne peut pas avoir d'instance.


Cependant, les classes abstraites sont des types. On peut déclarer une variable ou un paramètre d'un type abstrait. Le mécanisme de liaison tardive permettra d'invoquer la méthode correcte une fois que la variable ou le paramètre désignera une instance d'une classe concrète dérivée. Supposons par exemple que nous décidions d'attribuer de façon interne à toute forme géométrique un nom, qui est une chaîne de caractères. Au lieu de modifier la classe Forme définie plus haut, on peut l'étendre en une classe FormeNommee, par l'addition d'un champ de type String. Cette nouvelle classe hérite de la méthode abstraite translater(), donc est elle-même abstraite :

abstract class FormeNommee extends Forme {
  private String nom;
  FormeNommee(String nom) {
    this.nom = nom;
  }
  FormeNommee() {
    this.nom = "";
  }
  String getNom() {
    return nom;
  }
}

Notons qu'une classe abstraite peut avoir des constructeurs, mais qu'ils ne peuvent pas être invoqués pour créer des objets et qu'une classe abstraite peut avoir des méthodes non abstraites. Un constructeur d'une classe abstraite est généralement invoqué par un constructeur d'une classe dérivée, explicitement par super(...), ou implicitement, ce qui équivaut à super().


Modifions maintenant les définitions des types concrets Point, Cercle et Rectangle pour les faire dériver de FormeNommee au lieu de Forme. Ainsi, Point dérive de FormeNommee, qui dérive de Forme. Les types concrets Point, Cercle, etc., héritent maintenant du champ nom et de la méthode getNom. Il faut par conséquent ajouter un paramètre de type String au constructeur, et invoquer le constructeur de la classe parente, au moyen de super(nom)  :

class Point extends FormeNommee { 
  double x, y;
  Point(double x, double y, String nom) {
    super(nom);
    this.x = x;
    this.y = y;
  }
  double surface() {
    return 0;
  }
}

Un membre privé n'est jamais hérité. Par exemple, le champ privé nom défini dans FormeNommee n'est pas hérité par Point : si p est une variable de type Point, l'expression p.nom n'est pas correcte (figure 1.10). De plus, il n'y a aucun moyen pour contourner ce caractère privé ; il est inutile (contrairement au cas du masquage des champs) d'essayer un transtypage en FormeNommee : l'expression (FormeNommee)p.nom est également incorrecte, puisque (FormeNommee)p est de type FormeNommee, et que nom en est un champ privé.


 \begin{figurette}% latex2html id marker 2403
\begin{center}
\leavevmode
\fbox{...
...Nommee} : le champ \texttt{nom} n'est pas hérité.}
\end{center} \end{figurette}


La classe dérivée ne peut accéder directement aux champs privés de la classe parente, mais peut éventuellement y accéder si elle hérite de méthodes d'accès. Dans l'exemple précédent, le champ nom n'est pas hérité, mais la méthode getNom() est héritée. Par suite, si p est un point, l'expression p.nom est incorrecte, mais l'expresssion p.getNom() est correcte.


next up previous contents index
Next: Liaison tardive Up: Héritage Previous: Héritage
R. Lalement
2000-10-23