Introduction aux classes ActionScript 2 ( 2ème partie )
L'héritage sur des propriétés d'occurrences de class commence à être convenablement assimilé, continuons avec les méthodes d'occurrences de class. Comme nous l'avons vu, une class fille peut accéder aux propriétés et méthodes de la class mère, mais que ce passe t'il lorsque nous invoquons une méthode de MaClass
à partir d'une occurrence de MaClassX
, surtout, lorsque cette méthode gère des propriétés d'occurrences de MaClass
:
/*MaClass.as*/ class MaClass { private var n; public function MaClass () { trace ("MaClass()") n = 111; } public function nombre ():Void { trace ("MaClass().nombre() : "+n) } } /*MaClassX.as*/ import MaClass; class MaClassX extends MaClass { private var n; public function MaClassX () { trace ("MaClassX()") n = 777; } } /*Usage : */ import MaClassX; var i:MaClassX = new MaClassX(); i.nombre() var j:MaClass = new MaClass(); j.nombre (); /*Résultats : */ /* MaClass() MaClassX() MaClass().nombre() : 777 MaClass() MaClass().nombre() : 111 */
On voit bien, que l'occurrence de MaClassX
appelle une méthode de MaClass
, mais que la propriété qui est pris en compte est celle de l'instance crée, et non celle de sa superClass.
Surchargeons donc la méthode MaClass.nombre ()
dans MaClassX ()
:
/*Modification de MaClassX : */ import MaClass; class MaClassX extends MaClass { private var n; public function MaClassX () { trace ("MaClassX()") n = 777; } public function nombre ():Void { trace ("MaClassX().nombre() : "+n*2) } } /*Usage : */ import MaClassX; var i:MaClassX = new MaClassX(); i.nombre(); /*Résultats : */ /* MaClass() MaClassX() MaClassX().nombre() : 1554 */
MaClass().nombre()
n'est plus utilisé. Sauf, si on utilise super
:
/*Modification de MaClassX : */ import MaClass; class MaClassX extends MaClass { private var n; public function MaClassX () { trace ("MaClassX()") n = 777; } public function nombre ():Void { super.nombre(); trace ("MaClassX().nombre() : "+n*2) } } /*Usage : */ import MaClassX; var i:MaClassX = new MaClassX(); i.nombre(); /*Résultats : */ /* MaClass() MaClassX() MaClass().nombre() : 777 MaClassX().nombre() : 1554 */
L'utilisation de super.MéthodeDeMaClass
permet donc d'imposer l'exécution de la méthode de MaClass
, même si cette méthode a été surchargée, mais elle continue de ne fonctionner qu'avec les propriétés de MaClassX
.
Pour bien comprendre les différences entre propriétés d'occurrences et de class, mélangeons un peu les 2, ouvrez bien les yeux, car il se passe beaucoup de choses, cet exemple, c'est un bon récapitulatif :
/*MaClass.as */ class MaClass { /* variables d'occurrence */ private var nSurcharge:Number; private var nNonSurcharge:Number; /* variables de class */ private static var sTypeSurcharge:String="MaClass"; private static var sTypeNonSurcharge:String="MaClass !!"; public function MaClass () { trace ("MaClass()") nSurcharge = 111; nNonSurcharge = 222; } private function nombreSurchargee ():Number { return nSurcharge; } private function typeSurchargee ():String { return sTypeSurcharge; } } /*MaClassX.as */ import MaClass; class MaClassX extends MaClass { /* variables d'occurrence surchargée*/ private var nSurcharge:Number; /* variables de class surchargée*/ private static var sTypeSurcharge:String="MaClassX"; public function MaClassX () { trace ("MaClassX()") nSurcharge = 777; } /* Pour tester la surcharge de propriété */ public function getVarOccurrenceSurchargee ():Void { trace ("MaClassX() getVarOccurrenceSurchargee : "+nSurcharge) } public function getVarOccurrenceNonSurchargee ():Void { trace ("MaClassX() getVarOccurrenceNonSurchargee : "+nNonSurcharge) } public function getVarClassSurchargee ():Void { trace ("MaClassX() getVarClassSurchargee : "+sTypeSurcharge) } public function getVarClassNonSurchargee ():Void { trace ("MaClassX() getVarClassNonSurchargee : "+sTypeNonSurcharge) } public function getVarOccurrenceMereSurchargee ():Void { trace ("MaClassX() getVarOccurrenceMereSurchargee : "+super.nombreSurchargee()) } public function getVarClassMereSurchargee ():Void { trace ("MaClassX() getVarClassMereSurchargee : "+super.typeSurchargee()) } } /*Usage : */ import MaClassX; var i:MaClassX = new MaClassX(); trace ("1 :") i.getVarOccurrenceSurchargee (); trace ("2 :") i.getVarOccurrenceNonSurchargee (); trace ("3 :") i.getVarClassNonSurchargee(); trace ("4 :") i.getVarClassSurchargee (); trace ("5 :") i.getVarOccurrenceMereSurchargee(); trace ("6 :") i.getVarClassMereSurchargee (); /*Résultats : */ /* MaClass() MaClassX() 1 : MaClassX() getVarOccurrenceSurchargee : 777 2 : MaClassX() getVarOccurrenceNonSurchargee : 222 3 : MaClassX() getVarClassNonSurchargee : MaClass !! 4 : MaClassX() getVarClassSurchargee : MaClassX 5 : MaClassX() getVarOccurrenceMereSurchargee : 777 6 : MaClassX() getVarClassMereSurchargee : MaClass */
N'ayez pas peur ^^, analysons tranquillement ces résultats :
- 1 : La variable d'occurrence est surchargée, donc on affiche celle redéfinie dans le constructeur
MaClassX()
- 2 : La variable d'occurrence n'est pas surchargée, donc on obtient celle définie dans le constructeur
MaClass()
- 3 : La variable de class n'est pas surchargée, donc on obtient celle définie dans le corps de
MaClass()
- 4 : La variable de class est surchargée, donc on obtient celle définie dans le corps de
MaClassX()
- 5 : La variable d'occurrence de
MaClass
étant surchargée, impossible de récupérer sa valeur définie dansMaClass
, elle est écrasée. - 6 : La variable de class de
MaClass
est surchargée, pourtant, elle reste disponible, n'étant pas une variable d'occurrence de class.
On peut donc commencer à tirer des conclusions, une variable d'occurrence de class surchargée cesse d'exister, une variable de class surchargée reste disponible.
Maintenant, faites très attention :
/*MaClass.as */ class MaClass { /* variables de class */ private static var sTypeSurcharge:String="MaClass"; public function MaClass () { trace ("MaClass()") } public function typeSurchargee ():String { return sTypeSurcharge; } } /*MaClassX.as */ import MaClass; class MaClassX extends MaClass { /* variables de class surchargée*/ private static var sTypeSurcharge:String="MaClassX"; public function MaClassX () { trace ("MaClassX()") } } /*Usage : */ import MaClassX; var i:MaClassX = new MaClassX(); trace (i.typeSurchargee()) /*Résultats : */ /* MaClass() MaClassX() MaClass */
Aie, Pourquoi cela ne me renvoie pas MaClassX
?
Parce que, à la compilation, sTypeSurcharge;
n'est pas assigné à un objet particulier, or le compilateur lit qu'une variable statique du même nom existe pour la class MaClass
, il décide donc d'assigner cette variable statique à MaClass();
, le code return sTypeSurcharge;
est remplacé par return MaClass.sTypeSurcharge;
Notez bien ce comportement, car c'est la cause principale de confusion : une variable d'occurrence maVar
est compilée en this.maVar
, une variable de class comme maVarClass
est compilée en MaClass.maVarClass
.
Nous verrons prochainement l'utilisation de méthodes statiques pour contrôler tout ça.
On va se refroidir le CPU tout doucement ^^, avec quelques petits rappels d'optimisation qui ne font pas de mal :
// Ne faites pas : var a:Array = [1,2,3,4,5,6,7,8,9,10] for (var i:Number=0;i<a.length;i++) { //à chaque incrémentation flash va recalculer la longueur du array } // mais plutot : var a:Array = [1,2,3,4,5,6,7,8,9,10] var nA:Number = a.length for (var i:Number=0;i<nA;i++) { //La longueur du tableau est calculée une fois pour toute } // vous y gagnerez en vitesse d'exécution. // ne faites pas : var i = 0; // mais : var i:Number = 0; // cela n'alourdira pas le poids de votre fla, car le typage fort ne sert qu'à la compilation, et non à l'exécution.
On en a fini avec les propriétés, voyons maintenant les différences entre méthodes statiques et d'occurrence :
/*MaClass.as*/ class MaClass { private static var sNom:String="MaClass"; public function MaClass () { trace ("MaClass()") } public static function get nom ():String { return sNom; } } /*MaClassX.as*/ import MaClass; class MaClassX extends MaClass { private static var sNom:String="MaClassX"; public function MaClassX () { trace ("MaClassX()") } } /*Usage : */ import MaClassX; trace (MaClass.nom) trace (MaClassX.nom) /*Résulats : */ /* MaClass MaClass */
Rappelez-vous ce qu'il a été dit plus haut sur la résolution de l'assignation d'une variable statique à la compilation …
On voit aussi que les constructeurs de class non pas été appelé, donc qu'il n'existe aucune occurrence de ces class. Comment puis-je faire pour qu'a partir de MaClassX, on puisse accéder à la fois à MaClass.sNom
et à MaClassX.sNom
? Il faut surcharger MaClass.nom
:
/*Modification de MaClassX.as*/ import MaClass; class MaClassX extends MaClass { private static var sNom:String="MaClassX"; public function MaClassX () { trace ("MaClassX()") } public static function get nom ():String { return sNom; } public static function get nomMere ():String { return MaClass.nom; } } /*Usage : */ import MaClassX; trace (MaClassX.nom) trace (MaClassX.nomMere) /*Résulats : */ /* MaClassX MaClass */
Ici, nous n'avons pas utilisé super.nom; pour lancer la méthode surchargée de la class mêre, car c'est une méthode de class, et non une méthode d'occurrence. Si on avait mis return super.nom;
au lieu de return MaClass.nom;
, on aurait eu le droit à 'super' is not accessible from this scope.
