Expr
. En effet le code de la méthode eval
n'est pas défini.
(La réponse, il n'y a pas de constructeur n'est pas vraiment bonne,
cf. la question 4, et penser au constructeur par défaut
Expr()
.)Expr
, et de fait on ne pourra construire des objets de ces
classes filles que si la méthode eval est définie.
C'est tout le sens de la méthode déclarée abstraite.Reader
que nous connaissons déjà est en
fait abstraite. Une de ses classes filles est par
exemple StringReader
.
private Expr parseP() { Expr r = parseF() ; while (tok.nature == Token.MUL || tok.nature == Token.DIV) { Token op = tok ; step() ; Expr f = parseF() ; if (op.nature == Token.MUL) r = new Mul (r, f) ; else r = new Div (r, f) ; } return r ; } |
class Int extends Expr { private int me ; Int (int i) { me = i ; } int eval(Env e) { return me ; } public String toString() { return Integer.toString(me) ; } } class Id extends Expr { private String me ; Id (String s) { me = s ; } int eval(Env e) { return e.get(me) ; } public String toString() { return me ; } } |
Object
dont toutes les classes héritent
implicitement. Si on ne la redéfinissait pas, l'affichage d'une
expression
La classe Let
est à peine plus complexe.
class Let extends Expr { private String x ; private Expr ex, e ; Let (String x, Expr ex, Expr e) { this.x = x ; this.ex = ex ; this.e = e ; } int eval(Env env) { int vx = ex.eval(env) ; return e.eval(env.add(x,vx)) ; } public String toString() { return "LET (" + x + ", " + ex + ", " + e + ")"; } } |
Expr
.toString
essentiellement identiques.)
On remarque que la méthode (concrète) toString de
Binop
appelle la méthode abstraite getOp sans
complexe aucun.
class Add extends Binop { Add (Expr arg1, Expr arg2) { super(arg1,arg2) ; } String getOp() { return "+" ; } int eval(Env e) { return arg1.eval(e) + arg2.eval(e) ; } } class Sub extends Binop { Sub (Expr arg1, Expr arg2) { super(arg1,arg2) ; } String getOp() { return "-" ; } int eval(Env e) { return arg1.eval(e) - arg2.eval(e) ; } } |
super(arg1,arg2)
.Binop
à la spécification de signatures de méthodes
dynamiques publiques (cf. supra).
Mais l'héritage simple de Java (on hérite d'une seule classe) est
parfois limitant, il faut recourir aux interfaces si on souhaite
réaliser deux fonctionalités distinctes spécifiées indépendamment.