J´ai créé une classe Vector qui comprends nottament comme fonctions membres :
/ / Add ( without modification )
Vector operator+( const Vector & )
{ return Vector( x+src.x, y+src.y, z+src.z ) ; }
// Add ( with modification )
Vector operator+=( const Vector & )
{ x+=src.x; y+=src.y; z+=src.z; return *this; }
// Sub ( without modification )
Vector operator-( const Vector & )
{ return Vector( x-src.x, y-src.y, z-src.z ) ; }
// Sub ( with modification )
Vector operator-=( const Vector & )
{ x-=src.x; y-=src.y; z-=src.z; return *this; }
( les fonctions sont inlkine dans le . h, d´ou l´absence de " Vector::" )
Mais losrque j´exécute le programme suivant :
using namespace std;
int main( void )
{
Vector v1( 18.0, 20.0, 78.0 ) , v2( 2.0, 51.0, 27.0 ) ;
cout < < ( v1+v2).x < < " " < < ( v1-=v2).x < < endl;
return 0;
}
J´obtiens " 18 16", alors que si je supprime la partie ( v1-=v2).x, et que je ne garde que ( v1+v2).x, j´obtiens bel et bien " 20". Plusieurs combinaison de ce type produisent des résultats fantaisistes, pourquoi ? Le problème semble venir desopérateurs += et -=...
il faudrait vérifier dans le standard, mais je crois que ton expression melangeant + et -= a un comportement non défini. Donc trace au debugger pour vérifier, mais je pense qu´avec ton compilo v1 -= v2 est évalué en premier, du coup v1.x devient 16, et ensuite v1 + v2 est évalué, qui vaut alors 18.
avec un autre compilo qui évaluerait dans un autre ordre le résultat pourrait etre différent.
procède pas étape élémentaire pour lever toute ambiguité.
Pourtant j´utilise Visual C++ . net 2002.
Mais pourquoi exécuterais il -= avant le + ?
Il effectue un appel d´opérateurs en cascades, donc le + est traité avant le -= théoriquement...
" Il effectue un appel d´opérateurs en cascades, donc le + est traité avant le -= théoriquement..."
ben non, ça n´a rien de sûr du tout ça justement ; l´ordre d´évaluation ne correspond généralement que peu à l´ordre d´apparation dans le code, ça peut aussi dépendre d´option de compilation : à moins de faire les calls à main en asm, c´est pas évident du tout.
vu que c´est variable d´un compilo à l´autre, on évite d´utiliser les expressions faisant intervenir une variable et la meme modifiée.
trace au debugger pour vérifier l´ordre d´appel.
avec des pre/post ++/-- et des = on fait souvent des expressions qui peuvent donner des résultats variables selon l´évaluation ; une seule façon de procéder, découper les calculs sur plusieurs lignes pour etre sûr de l´ordre.
C´est bizarre...
Quand on surcharge l´opérateur de sortie standard, on fait souvent :
ostream &<<( ostream &, . .. )
{
sortie < < . .. ;
return sortie;
}
Qui implique que les expreesions soient traiter dans l´ordre de leur écriture.
Les types standard n´utiliseraient donc pas ce schéma ?
Qui implique que les expreesions soient traiter dans l´ordre de leur écriture.
Nope pas du tout: ( extraits de la doc iso c++)
" Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. "
Lag-it, c´est tres dangereux de faire çà. L´ordre de resolution d´une expression dépend totalement du compilateur et n´est absolument pas normalisé, je te conseil donc vivement de ne jamais utiliser les operateur += -= / = *= de la sorte car tu auras a coup sur des surprises.
Autre chose qui n´a rien a voir, je te conseile de retourner une référence à chaque fois que tu retourne *this
ex: Vector& operator-=( const Vector & )
{ x-=src.x; y-=src.y; z-=src.z; return *this; }
Ensuite, pour tes operateurs ´Without modification´, déclare les en ´friend´, ca parait plus coherent, car une fonction qui ne traite que des parametres sans meme utiliser sont contenu n´a aucun sens en C++.
Voilà, j´espere que çà pourra t´aider
Ca parait bete, mais tu viens d´éviter d´alouer Vector en pile pour le copier et le detruire aussitot dans ton parametre de retour.
Petite erreur de dactylo
Lag-it, c´est tres dangereux de faire çà. L´ordre de resolution d´une expression dépend totalement du compilateur et n´est absolument pas normalisé, je te conseil donc vivement de ne jamais utiliser les operateur += -= / = *= de la sorte car tu auras a coup sur des surprises.
Autre chose qui n´a rien a voir, je te conseile de retourner une référence à chaque fois que tu retourne *this
ex: Vector& operator-=( const Vector & )
{ x-=src.x; y-=src.y; z-=src.z; return *this; }
Ca parait bete, mais tu viens d´éviter d´alouer Vector en pile pour le copier et le detruire aussitot dans ton parametre de retour.
Ensuite, pour tes operateurs ´Without modification´, déclare les en ´friend´, ca parait plus coherent, car une fonction qui ne traite que des parametres sans meme utiliser sont contenu n´a aucun sens en C++.
Voilà, j´espere que çà pourra t´aider
kUfa > Oui, c´est pour ca que je demandais si les opérateurs standard suivaient ce schéma.
HS_DIno > C´est noté pour le renvoi de référence.
Sinon les without modification, pourquoi les déclarer en friend ? Je ne connais pas trop l´usage de ce mot-clé, hormis dans la surcharge des opérateurs à droite.
Merci à vous ![]()
opérateurs friend ou pas, débat sans fin, y´a les partisans, y´a les opposants :/
moi je suis plutôt " pas friend", les membres de l´objet étant utilisés dans le corps de l´opérateur, mais c´est surtout question de préférence il me semble.
Enfin si qqun voit un réel avantage à utiliser des op. friend, ou l´inverse, je suis tout ouïe.
sinon, pour les += -= " with modifications", j´ai plutôt tendance à returner void, c´est pas forcément plus contraignant et ça évite d´enchainer des expressions avec problème éventuel d´éval, comme dans l´ex. de lag-it.
là encore, tous les points de vue se défendent.
" Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified."
Quelqu´un pourrait éclaircir ce passage ?
Car j´ignorais cette partie de la norme ( je connais bien celle du C, mais peu celle du C++ )
Oui, c´est pour ca que je demandais si les opérateurs standard suivaient ce schéma.
Tout depends du compilo, vraiment..
Sinon perso ++"pas friend", sauf quand vraiment necessaire, surtout pour des pbs de design ( je vous conseille le c++ faq lite)
ben ça dit exactement ce qu´on a expliqué, que l´ordre d´évaluation des opérateurs ou sous-expressions n´est pas défini par le standard ; ça reste donc " compilo dépendant".
Il faudrait voir les cas précisés par la norme, puisqu´il est dit " except where noted" . ..
Je vous laisse regarder ( pas le temps moua ; )
http://www.kuzbass.ru/docs/isocpp/
dans la partie expressions
Merci, j´irai voir ca.
Sinon j´ai un petit truc qui me chagrine :
J´ai créé une classe Vector et une classe Vertex et je fournis à chacune 3 constructeurs : 1 avec des ccordonnées float, l´autre avec un Vector ou un Vertex ( constucteur de copie ) et un dernier permettant de convertir un Vector en Vertex et un Vertex en Vector.
Ca donne ca pour le Vertex :
Vertex( const Vector & )
{ x = src.x; y = src.y ; z = src.z; }
Ca ne pose aucun problème pour la création d´un Vector à partir d´un Vertex, mais dans le cas de la création d´un Vertex à partir d´un Vector ( cas plus haut ) , le compilateur refuse de compiler mon fichier et me sort :
error C2334: jetons inattendus avant ´{´ ; corps apparent de la fonction ignoré
error C2629: ´Vertex ( ´ inattendu
Sachant que :
[Compiler Error C2334]
" jetons inattendus avant ´: ou {´; corps apparent de la fonction ignoré"
Cette erreur se produit après une autre erreur, pour les fonctions membres définies dans leur classe.
Exemple
/ / C2334.cpp
struct s1 { / / in a cpp file
s1(s1 func hello) { / / C2334
}
};
[Compiler Error C2629]
´token ( ´ inattendu
Une erreur de syntaxe rend l´instruction ambiguë.
Cause possible
Mélange de syntaxe de déclaration et d´expression.
Exemple
/ / C2629.cpp
class A
{
};
class B
{
public:
int ( A::*apmfi)(), ( A::*apmfi2)();
};
int ( (A::*)(B::*)bpmapmfi)() = &::apmfi; / / C2629
Et ce, même en utilisant une déclaration préliminaire " class Vector;"
Qu´est ce qui ne va pas ?
Tu mets le corps des constructeurs dans le . hpp?
Non, dasn un . h classique.
Les . h/.hpp sont des headers, mais bcp de personnent ont la mauvaise habitude de mettre le corps des fonctions dans ces headers. Du coup, une modif dans le . h, et hop faut recompiler tous les . c qui incluent ce . h....
Ex de qqchose qui ne peut pas fonctionner:
class B;
class A
{
public:
void toto( B& test )
{
cout < < B.valeur; / ** erreur */
}
};
class B
{
public:
int valeur;
};
Par contre ca ca fonctionnera:
/ ** dans le . hpp */
class B;
class A
{
public:
void toto( B& test ) ;
};
class B
{
public:
int valeur;
};
/ ** dans le . cpp */
void A::toto( B& test )
{
cout < < B.valeur;
}
friend a l´avantage de permettre de fonctionner quelque soit l´ordre.
Ex : Si tu veux multiplier un veteur par un scalaire :
Vector v(1,2,3),a;
float s = 4;
a = v * s; / / fonctionne si Vector::operator*(float)
a = s * v; / / fonctionne pas car le float est a gauche !
Mais grace au friend:
friend Vector::operator(Vector, float)
Et ca ca marche pour les deux cas situé plus haut. Ca sert a çà le friend, c´est absolument pas une histoire de bien ou de pas bien, ou de propre ou de pas propre, ou de j´aime ou j´aime pas, c´est juste que c´est comme çà qu´il faut faire sinon ca marche pas ! ![]()
oui j´ai oublié de préciser que si je fais mon malin avec mes ´friend´ c´est juste parce que je l´ai appris le mois dernier a l´école, sinon j´etais comme vous je n´utilisais jamais ce mot clé : trop caca quand on ne sait pas l´utiliser ! ![]()