Rechercher : dans
Par :

Surcharge d'operateur en c++

Dernière réponse le 18 mar 2008 à 13:14:36 lapomme, le 13 mar 2008 à 23:01:00 
 Signaler ce message aux modérateurs

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?

Configuration: Linux
Firefox 2.0.0.12

Meilleures réponses pour « surcharge d'operateur en c++ » dans :
Surcharge des opérateurs Voir Surcharge des opérateurs Comme la plupart des langages, le C++ fournit un ensemble d’opérateurs pour manipuler ses types intégrés (int, float, char, etc.). Vous savez déjà, par exemple, que x+y*z se traduit par « multiplier y et z puis ajouter le...
Entrées/sorties : Les flux en C++ VoirEntrées/sorties : les flux en C++ 1. Ouvrir un fichier en lecture 1.1 Ouverture du fichier "donnees.txt" en lecture 1.2 Lecture du contenu de "donnees.txt" 2. Ouvrir un fichier en écriture 2.1 Ouverture du fichier "donnees.txt" en...
Les fonctions en C++ : surcharge et paramètres par défaut. VoirLes fonctions en C++ : surcharge et paramètres par défaut. 1. La surcharge de fonctions et méthodes de classes, dont le constructeur 2. Utilisation des paramètres par défaut En C++, une même fonction ou méthode de classe peut être...
Les files en langage C VoirLes files - Premier Entré Premier Sorti Requis I. INTRODUCTION II. Définition III. La construction du prototype d'un élément de la file IV. Opérations sur les files A. Initialisation B. Insertion d'un élément dans la file C. Oter un...
Langage C - Les opérateurs VoirQu'est-ce qu'un opérateur ? Les opérateurs sont des symboles qui permettent de manipuler des variables, c'est-à-dire effectuer des opérations, les évaluer, etc. On distingue plusieurs types d'opérateurs : les opérateurs de calcul les opérateurs...
Langage C++ - Les opérateurs VoirQu'est-ce qu'un opérateur ? Les opérateurs sont des symboles qui permettent de manipuler des variables, c'est-à-dire effectuer des opérations, les évaluer, etc. On distingue plusieurs types d'opérateurs : les opérateurs de calcul les opérateurs...
Les constructeurs et les destructeurs en langage C++ VoirLa notion de constructeur Le constructeur est la fonction membre appelée automatiquement lors de la création d'un objet (en statique ou en dynamique). Cette fonction membre est la première fonction membre à être exécutée, il s'agit donc d'une...

1

mamiemando, le 14 mar 2008 à 10:28:26

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

Répondre à mamiemando

2

lapomme, le 14 mar 2008 à 11:25:55

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;
};

Répondre à lapomme

4

kilian, le 14 mar 2008 à 13:36:34

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;
}

Répondre à kilian

5

lapomme, le 14 mar 2008 à 14:04:11

Merci beaucoup pour ton explication kilian.
J'avais effectivement fait l'erreur de les créér en tant que méthodes.

Répondre à lapomme

3

=[Cvrd]=Tassin, le 14 mar 2008 à 11:46:23

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) -- Alex pour vous servir --

-- N'oubliez pas de mettre vos sujets en "Résolu" lorsque vous avez la réponse ;-) --

Répondre à =[Cvrd]=Tassin

6

mamiemando, le 15 mar 2008 à 01:12:16

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

Répondre à mamiemando

7

kilian, le 17 mar 2008 à 13:17:29

Aurais-je dit une bêtise? Je vois pas en quoi ce que je disais était faux...

Répondre à kilian

8

mamiemando, le 18 mar 2008 à 09:33:44

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

Répondre à mamiemando

9

kilian, le 18 mar 2008 à 10:39:54

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 :-)

Répondre à kilian

10

 mamiemando, le 18 mar 2008 à 13:14:36

Pas de souçis ;-)

Répondre à mamiemando
Collection CommentÇaMarche.net