Surcharge d'operateur en c++

Résolu/Fermé
lapomme - 13 mars 2008 à 23:01
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 18 mars 2008 à 13:14
Bonjour,
J'ai une classe vector qui represente des vecteurs et j'ai défini quelque opérateur.
Par exemple je peux faire u + v ou u * 3
Par contre je n'arrive pas à faire 3 * u.
Est-ce qu'il est possible de surcharger de cette façon? si oui comment?

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
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 :-)
1
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
14 mars 2008 à 10:28
Dans un .hpp pour multiplier un scalaire T1 et un vecteur dans T2 :
#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
0
Desolé, j'ai un peu de mal à comprendre ton exemple.
En fait quand je parle de classe vector, je ne parle pas de std::vector.
J'ai créé ma propre classe vector:

class Vector
{
public:
Vector(x,y);
Vector operator*(float);
...
private:
float x;
float y;
};
0
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
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:
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;
}
0
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
Merci beaucoup pour ton explication kilian.
J'avais effectivement fait l'erreur de les créér en tant que méthodes.
0
Utilisateur anonyme
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)
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
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)
#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
0
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
Aurais-je dit une bêtise? Je vois pas en quoi ce que je disais était faux...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
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
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
18 mars 2008 à 13:14
Pas de souçis ;-)
0