Surcharge d'operateur en c++
Résolu/Fermé
lapomme
-
13 mars 2008 à 23:01
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 18 mars 2008 à 13:14
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 18 mars 2008 à 13:14
6 réponses
kilian
Messages postés
8731
Date d'inscription
vendredi 19 septembre 2003
Statut
Modérateur
Dernière intervention
20 août 2016
1 527
18 mars 2008 à 10:39
18 mars 2008 à 10:39
Ah ok je vois ce que tu veux dire. En fait tel qu'il a présenté son problème, je pensais qu'il recodait la classe Vector en cours de prog. Donc pour moi il partait de zero et n'utilisait pas la librarie standard (cf message 2).
Mais tu as raison de pinailler, c'est vrai que je suis dans le faux en disant qu'il faut que l'operator soit implémenté à l'extérieur. Ce que je voulais signifier, c'était plus exactement que cet operator devait être une fonction et non pas une méthode. Ensuite par habitude je rajoutais qu'il faut que l'implémentation soit à l'extérieur, mais c'est finalement plus un tic de propreté qu'une necessité :-)
A bientôt :-)
Mais tu as raison de pinailler, c'est vrai que je suis dans le faux en disant qu'il faut que l'operator soit implémenté à l'extérieur. Ce que je voulais signifier, c'était plus exactement que cet operator devait être une fonction et non pas une méthode. Ensuite par habitude je rajoutais qu'il faut que l'implémentation soit à l'extérieur, mais c'est finalement plus un tic de propreté qu'une necessité :-)
A bientôt :-)
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
14 mars 2008 à 10:28
14 mars 2008 à 10:28
Dans un .hpp pour multiplier un scalaire T1 et un vecteur dans T2 :
Bonne chance
#include <vector> template <typename T1,typename T2> std::vector<T2> operator*(const T1 & x,const std::vector<T2> & y){ std::vector<T2> z(y.size()); for(std::size_t i=0;i<n;++i) z[i] = x * y[i]; return z; }
Bonne chance
kilian
Messages postés
8731
Date d'inscription
vendredi 19 septembre 2003
Statut
Modérateur
Dernière intervention
20 août 2016
1 527
>
lapomme
14 mars 2008 à 13:36
14 mars 2008 à 13:36
Salut,
Il ne faut pas que ce soit une méthode de ta classe Vector mais une fonction et une fonction friend de sucroit. Car cette fonction doit pouvoir avoir accés aux membres privés de vector.
Pourquoi une fonction et pas une méthode?
Parce qu'avec une surcharge par méthode, l'opérateur de gauche est obligatoirement l'objet (ici un objet Vector en l'occurence).
Avec une surcharge par fonction, c'est toi qui décide exactement des paramètres et de leur place.
Ca donnerais ça:
Pour l'implémentation, attention de ne pas mettre ça dans l'espace de nom de Vector, car c'est une fonction globale et pas une méthode de Vector, donc pas de Vector::operator*, juste operator*
Il ne faut pas que ce soit une méthode de ta classe Vector mais une fonction et une fonction friend de sucroit. Car cette fonction doit pouvoir avoir accés aux membres privés de vector.
Pourquoi une fonction et pas une méthode?
Parce qu'avec une surcharge par méthode, l'opérateur de gauche est obligatoirement l'objet (ici un objet Vector en l'occurence).
Avec une surcharge par fonction, c'est toi qui décide exactement des paramètres et de leur place.
Ca donnerais ça:
class Vector { public: Vector(x,y); Vector operator*(float); //Surcharge de type v*5 friend Vector operator*(float, vector); //Surcharge de type 5*v ... private: float x; float y; };
Pour l'implémentation, attention de ne pas mettre ça dans l'espace de nom de Vector, car c'est une fonction globale et pas une méthode de Vector, donc pas de Vector::operator*, juste operator*
Vector operator*(float f, Vector v) { Vector temp(v); //Il faut que tu aies prévu un constructeur par copie temp.x = v.x * f; temp.y = v.y *f; return temp; }
lapomme
>
kilian
Messages postés
8731
Date d'inscription
vendredi 19 septembre 2003
Statut
Modérateur
Dernière intervention
20 août 2016
14 mars 2008 à 14:04
14 mars 2008 à 14:04
Merci beaucoup pour ton explication kilian.
J'avais effectivement fait l'erreur de les créér en tant que méthodes.
J'avais effectivement fait l'erreur de les créér en tant que méthodes.
Utilisateur anonyme
14 mars 2008 à 11:46
14 mars 2008 à 11:46
Bonjour,
Essaye comme ceci
Vector operator * (float f,Vector v)
et ca réciproque :
Vector operator * (Vector v, float f)
(Pour info : http://www-ipst.u-strasbg.fr/pat/program/cpp/vecteur-simple.pdf)
Essaye comme ceci
Vector operator * (float f,Vector v)
et ca réciproque :
Vector operator * (Vector v, float f)
(Pour info : http://www-ipst.u-strasbg.fr/pat/program/cpp/vecteur-simple.pdf)
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
15 mars 2008 à 01:12
15 mars 2008 à 01:12
Bien que résolu je me permets de revenir sur le sujet car ce qu'à dit est faux (tu peux tout à fait implémenter * sur un vecteur), parce que tassin a dit un cas particulier de ce que j'ai donné, et parce que manifestement le code que je t'ai donné n'est pas clair.
Un exemple plus parlant
On va enrichir ce que j'ai donné en <1> pour illustrer l'utilisation (accessoirement rajouter l'instruction en gras qui manquait)
Donne a l'exécution :
Ok revenons sur le code. On a définit un opérateur template
* qui prend en membre de gauche un objet de type T1 et un vecteur sur T2
<< qui prend un flux ouvert en écriture (dont std::cout et les std::ofstream) pour les vecteurs de type T
Quelques rappels sur les templates
Un type template peut être remplacé selon les besoins du compilateur par n'importe quel type. En l'occurrence no va compiler dans cet exemple :
(1) Pour v: std::vector<int> operator*(const int & x,const std::vector<int> & y)
(2) Pour w: std::vector<double> operator*(const int & x,const std::vector<double> & y)
Si j'avais multiplié v (ou w) par un scalaire non entier (par exemple un float) j'aurais compilé des produits supplémentaires.
Etant donné que le compilateur ne sait quels types vont remplacer les types template, et pour quels type il va devoir compiler une fonction, une fonction template est
- soit implémentée dans un header inclu par chaque fichier source utilisant la fonction template
- soit implémentée dans le fichier source qui sera le seul à pouvoir utilisé la fonction template
Quel intérêt me direz vous ? Tout simplement, je n'écris qu'une fois le produit d'un vecteur par un scalaire et le compilateur sait directement de quoi je parle. Dans la méthode de Tassin (en admettant que Vector corresponde par exemple à typedef std::vector<int> Vector) le produit n'est défini que pour le produit d'un vecteur d'entiers par un flottant, ce qui est un peu dommage. Plutôt que d'écrire un opérateur à chaque fois que l'on manipule un type template, autant profiter de la puissance des templates.
L'exemple en détail
Pour v je calcule un vecteur produit d'entiers (voir opérateur (1)). Cela signifie que même si je multiplie le vecteur par un scalaire flottant, le vecteur calculé sera un entier (cf 3.1*v). C'est pourquoi on obtient seulement la partie entière.
Pour w je calcul un vecteur produit de flottants (voir opérateur (2)), ce qui explique pourquoi j'obtiens bien le résultat auquel on s'attend, ie un vecteir de flottant
J'insiste en particulier sur le fait que déclarer l'opérateur à l'extérieur de la classe revient à le déclarer à l'intérieur en tant que méthode (sauf que dans le premier cas on n'a pas accès aux membres protégés ou privés de la classe). Ainsi :
marche et retourne bien :
Ainsi les opérateurs + et - ont été tantôt dans plop_t et tantôt dehors. Leur utilisation est cependant strictement similaire par la suite.
En espérant que ce soit plus clair :-)
Bonne chance
Un exemple plus parlant
On va enrichir ce que j'ai donné en <1> pour illustrer l'utilisation (accessoirement rajouter l'instruction en gras qui manquait)
#include <vector> #include <ostream> #include <iostream> template <typename T1,typename T2> std::vector<T2> operator*(const T1 & x,const std::vector<T2> & y){ const std::size_t n = y.size(); std::vector<T2> z(n); for(std::size_t i=0;i<n;++i) z[i] = x * y[i]; return z; } template <typename T> std::ostream & operator<<(std::ostream & out,const std::vector<T> & x){ const std::size_t n = x.size(); for(std::size_t i=0;i<n;++i) out << x[i] << ' '; return out; } int main(){ std::cout << "vecteur v" << std::endl; std::vector<int> v(5); v[0] = 1; v[1] = 3; v[2] = 4; v[3] = 2; v[4] = 7; std::cout << v << std::endl; std::cout << (2*v) << std::endl; std::cout << (3.1*v) << std::endl; std::cout << "vecteur w" << std::endl; std::vector<double> w(5); w[0] = 1; w[1] = 3; w[2] = 4; w[3] = 2; w[4] = 7; std::cout << w << std::endl; std::cout << (2*w) << std::endl; std::cout << (3.1*w) << std::endl; return 0; }
Donne a l'exécution :
vecteur v 1 3 4 2 7 2 6 8 4 14 3 9 12 6 21 vecteur w 1 3 4 2 7 2 6 8 4 14 3.1 9.3 12.4 6.2 21.7
Ok revenons sur le code. On a définit un opérateur template
* qui prend en membre de gauche un objet de type T1 et un vecteur sur T2
<< qui prend un flux ouvert en écriture (dont std::cout et les std::ofstream) pour les vecteurs de type T
Quelques rappels sur les templates
Un type template peut être remplacé selon les besoins du compilateur par n'importe quel type. En l'occurrence no va compiler dans cet exemple :
(1) Pour v: std::vector<int> operator*(const int & x,const std::vector<int> & y)
(2) Pour w: std::vector<double> operator*(const int & x,const std::vector<double> & y)
Si j'avais multiplié v (ou w) par un scalaire non entier (par exemple un float) j'aurais compilé des produits supplémentaires.
Etant donné que le compilateur ne sait quels types vont remplacer les types template, et pour quels type il va devoir compiler une fonction, une fonction template est
- soit implémentée dans un header inclu par chaque fichier source utilisant la fonction template
- soit implémentée dans le fichier source qui sera le seul à pouvoir utilisé la fonction template
Quel intérêt me direz vous ? Tout simplement, je n'écris qu'une fois le produit d'un vecteur par un scalaire et le compilateur sait directement de quoi je parle. Dans la méthode de Tassin (en admettant que Vector corresponde par exemple à typedef std::vector<int> Vector) le produit n'est défini que pour le produit d'un vecteur d'entiers par un flottant, ce qui est un peu dommage. Plutôt que d'écrire un opérateur à chaque fois que l'on manipule un type template, autant profiter de la puissance des templates.
L'exemple en détail
Pour v je calcule un vecteur produit d'entiers (voir opérateur (1)). Cela signifie que même si je multiplie le vecteur par un scalaire flottant, le vecteur calculé sera un entier (cf 3.1*v). C'est pourquoi on obtient seulement la partie entière.
Pour w je calcul un vecteur produit de flottants (voir opérateur (2)), ce qui explique pourquoi j'obtiens bien le résultat auquel on s'attend, ie un vecteir de flottant
J'insiste en particulier sur le fait que déclarer l'opérateur à l'extérieur de la classe revient à le déclarer à l'intérieur en tant que méthode (sauf que dans le premier cas on n'a pas accès aux membres protégés ou privés de la classe). Ainsi :
#include <iostream> class plop_t{ protected: unsigned x; public: plop_t(unsigned x0):x(x0){} unsigned get_x() const{ return x; } unsigned operator + (const unsigned y) const{ return x + y; // j'ai accès à x car je suis dans la classe } }; unsigned operator *(const plop_t & p,const unsigned y){ return p.get_x() * y; // je n'ai pas accès à x (protégé) } int main(){ plop_t p(69); std::cout << (p + 1) << std::endl; std::cout << (p * 2) << std::endl; return 0; }
marche et retourne bien :
70 138
Ainsi les opérateurs + et - ont été tantôt dans plop_t et tantôt dehors. Leur utilisation est cependant strictement similaire par la suite.
En espérant que ce soit plus clair :-)
Bonne chance
kilian
Messages postés
8731
Date d'inscription
vendredi 19 septembre 2003
Statut
Modérateur
Dernière intervention
20 août 2016
1 527
17 mars 2008 à 13:17
17 mars 2008 à 13:17
Aurais-je dit une bêtise? Je vois pas en quoi ce que je disais était faux...
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
18 mars 2008 à 09:33
18 mars 2008 à 09:33
Il ne faut pas que ce soit une méthode de ta classe Vector mais une fonction et une fonction friend de sucroit.
C'est juste cette phrase qui me dérangeait car :
1- c'est la classe std::vector (au lieu de Vector)
2- elle peut être méthode de std::vector si on s'autorise à modifier l'implémentation de cette classe (ou si on fait un héritage) si on veut écrire l'opérateur dans la classe
3- dans le cas particulier de std::vector on n'a de toute façon pas besoin d'accéder à des membres privés ou protégés pour ce genre d'opération (du moins tout est accessible via des accesseurs genre []), donc pas besoin de friend. On peut donc implémenter l'opérateur hors de la classe indiqué dans <6>. Bien que l'implémentation soit en dehors de la classe std::vector, elle est équivalente à une implémentation à l'intérieur de la classe elle-même.
Mais désolée je pinaille :p
C'est juste cette phrase qui me dérangeait car :
1- c'est la classe std::vector (au lieu de Vector)
2- elle peut être méthode de std::vector si on s'autorise à modifier l'implémentation de cette classe (ou si on fait un héritage) si on veut écrire l'opérateur dans la classe
3- dans le cas particulier de std::vector on n'a de toute façon pas besoin d'accéder à des membres privés ou protégés pour ce genre d'opération (du moins tout est accessible via des accesseurs genre []), donc pas besoin de friend. On peut donc implémenter l'opérateur hors de la classe indiqué dans <6>. Bien que l'implémentation soit en dehors de la classe std::vector, elle est équivalente à une implémentation à l'intérieur de la classe elle-même.
Mais désolée je pinaille :p
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
18 mars 2008 à 13:14
18 mars 2008 à 13:14
Pas de souçis ;-)