Soyez le premier à donner votre avis sur cette source.
Snippet vu 6 964 fois - Téléchargée 37 fois
/* On vous donne la classe A suivante : class A { private: int i_; public: A(int i) : i_(i){} void print() const {cout << "valeur A=" << i_ << endl;} }; On vous demande de supporter le "Use Case" suivant : int main(){ A a(0); a++.print(); (++a).print(); } 0) Question préliminaire : --------------------------- Quelle est l'arité de ++ dans a++ ? et dans ++a ? (l'arité d'un opérateur est son nombre de paramètres) la réponse dans les deux cas devrait être UN Donc, en l'implémentant comme méthode de la classe A, et en tenant compte du paramètre caché 'this', elle ne doit avoir aucun paramètre Comment différencier alors le cas a++ du cas ++a ? Les standards répondent à ce problème en imposant un paramètre 'int' à la version postfixée I) Commençons par le premier opérateur : ----------------------------------------- l'implémentation de la version postfixée de l'opérateur ++ Quel est le prototype ? Ecrivons la version complète de l'opérateur (sa vision compilateur) a++ est équivalent à a.operator++(int) Que doit faire cet opérateur ? d'abord incrémenter 'a', ensuite renvoyer l'ancienne valeur de 'a' On remarquera qu'ici, il est "NECESSAIRE DE CREER UN OBJET TEMPORAIRE" voici notre implémentation comme méthode de la classe A: ?A? operator++(int) { A clone(*this); //ceci est un appel au Ctor de copie de A //permet de mémoriser l'ancienne valeur ++i_; //incrémente l'objet courant return clone; //renvoie l'ancienne valeur } // ici appel au "DTOR DE L'OBJET TEMPORAIRE" où ?A? représente soit 'A', 'const A', 'A&' ou 'const A&' On élimine les pointeurs car le résultat de a++ est forcément un espèce de A Comment choisir ? Eliminons les références car l'objet renvoyé est temporaire (créé sur la pile) il disparait dès la sortie du bloc '}', il est "NECESSAIRE DE RENVOYER UNE COPIE" J'espère maintenant que vous êtes dégoutés du POST-FIXE ! Pour départager les ex-aequos (A et const A) voyons comment se comporte l'opérateur des types de base (l'int par exemple) Testons le code suivant : int i(0); i++++; Une erreur de compilation survient car l'opérateur ++ postfixé des 'int' attend une L-VALUE (Left-value). L-VALUE : variable possédant une zone de mémoire accessible en lecture/écriture donc en particulier, pas une variable temporaire, ni une const. En résumé, une variable pouvant être placée à gauche du signe = Ceci nous donne notre réponse : le type de retour DOIT être un 'const A' plutôt que 'A' pour être conforme au standards On peut alors tester le premier opérateur ainsi int main() { int i(0); //i++++; ne compile pas ++ requiert l-value A a(0); //a++++; // ne compile pas si operator++(int) retourne un const cout << "valeur i=" << i++ << endl;//renvoie 0 cout << "valeur i=" << i << endl;//renvoie 1 a++.print();//renvoie 0 : attention à bien prototyper la méthode print const a.print();//renvoie 1 return 0; } II) Deuxième opérateur : ----------------------------------------- Quel est le prototype de la version préfixée de l'opérateur ++ ? ++a est équivalent à a.operator++() Que doit faire cet opérateur ? d'abord incrémenter 'a', ensuite renvoyer la nouvelle valeur de 'a' On remarquera qu'ici, que l'on n'a pas besoin d'objet temporaire (COOL) voici notre implémentation comme méthode de la classe A: ?A? operator++() { ++i_; //incrémente l'objet courant return *this; //le renvoie } On peut renvoyer un 'A', 'const A', 'A&' ou 'const A&' Le meilleur pour les performances est de renvoyer par référence Voyons si elle doit être const ou non avec la même technique que précédemment on teste ++++i; ... et ça marche ! On peut donc retourner un A& (et c'est préférable pour imiter les types de base)
le i++ requiert de creer une variable temporaire, car on peut faire tableau[i++]; et i va exister dans 2 etat un etat non incrementé temporaire pour l'indice du tableau, et un etat incrementer pour la nouvelle valeur de i.
il faudrai transformer en asm une class integer refaite avec post incrementation et pre incrementation et la transformer en asm, en desactivant si possible les optimisations.
int *a=x;
b=*(++a); est beaucoup plus lente que b=*(a++);
equivalent a: (a= a0 b=d0 );
addq #1,a0
move.l (a0),d0
contre:
move.l (a0)+,d0
...
@+
Pour les opérations sur les types de données simples (int par exemple), la différence ne se situe pas dans l'opération elle - même (les codes asm sont équivalents) mais sur l'évaluation de l'expression. Je m'explique :
int i = 5;
( ++i == 5 ) est faux car l'incrémentation a lieu avant l'évaluation
int i = 5;
( i ++ == 5 ) est vrai car l'incrémentation a lieu après l'évaluation
J'espère que c'est clair...
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.