IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Comment surcharger l'opérateur () ?


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Points : 55
    Points
    55
    Par défaut Comment surcharger l'opérateur () ?
    Bonjour,

    J'ai créé une classe matrice pour inclure le calcul matriciel dans mon programme. Je sais que des librairies existent mais moi je veux pas les utiliser. Je tiens à le faire par moi-même.
    J'ai surchargé l'opérateur () pour pouvoir accéder a un élément tableau private. Voilà le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #ifndef MATRIX_H
    #define MATRIX_H
     
    #include <QVector>
     
    class Matrix
    {
    public:
        Matrix();
        void setSize(int rowNumber, int columnNumber);
        int rowCount();
        int columnCount();
        double operator()(int rowId, int columnId) const;
        double& operator()(int rowId, int columnId);
     
        void reverse();
        void transpose();
        double determinant();
        ~Matrix();
     
    private:
        int row;
        int column;
        QVector<double> data;
        double Det3x3Matrix(Matrix *M);
    };
     
    Matrix operator+(Matrix a, Matrix b);
    Matrix operator*(Matrix a, Matrix b);
     
    #endif // MATRIX_H

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    double Matrix::operator()(int rowId, int columnId) const
    {
        return data[column*rowId+columnId];
    }
     
    double& Matrix::operator()(int rowId, int columnId)
    {
        return data[column*rowId+columnId];
    }
    L'intérêt est de pouvoir déclarer une matrice M et d'appeler ses éléments avec M(0,0) ou M(2,3), etc... ça marche bien sauf si M est un pointeur. Cette fonction ne marche pas et je ne sais pas pourquoi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    double Matrix::Det3x3Matrix(Matrix *M)
    {
        double determinant = 0;
        if (M->rowCount() == M->columnCount()) // On vérifie que M est une matrice carrée
        {
            determinant =
                    M[0, 0] * (M[1, 1] * M[2, 2] - M[2, 1] * M[1, 2]) -
                    M[0, 1] * (M[1, 0] * M[2, 2] - M[2, 0] * M[1, 2]) +
                    M[0, 2] * (M[1, 0] * M[2, 1] - M[2, 0] * M[1, 1]);
        }
        return determinant;
    }
    Il ne comprend pas l'opérateur -. Normal car je ne l'ai pas surchargé. En revanche l'opération devrait se passer entre des double, et pas des Matrices. J'en conclu que M[0,0] ne renvoie pas un double mais une matrice apparament. Pourquoi????

    Merci de votre aide.

    Cordialement

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Déjà, tu vas me faire le plaisir de transformer toutes tes fonctions pour qu'elles prennent (quand elles en ont besoin) une matrice sous la forme d'une référence (de préférence constante, si ta fonction ne doit pas la modifier) et non sous la forme d'un pointeur ou -- pire -- d'une valeur.

    Cela n'a l'air de rien, mais cela te permettra d'éviter bien des soucis de performances (par rapport à la copie qui est effectuée quand tu la transmet par valeur) et de syntaxe (entre autres, quand il s'agit d'utiliser l'opérateur() sur un pointeur )

    Mais pour te donner une piste :
    Tu définis l'opérateur () sous une forme constante et sous une forme non constante de telle manière à ce qu'il te permet d'accéder à un élément particulier de ta matrice sur base de la ligne et de la colonne qu'il occupe, mais tu essayes d'utiliser l'opérateur[] pour accéder aux éléments dont tu as besoin pour calculer le déterminant... Il n'y a rien qui te choque dans cette explication
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Points : 55
    Points
    55
    Par défaut
    Si j'ai utilisé des crochets, c'est parce qu'il ne reconnait pas les parenthèses. Il me dit: M cannot be used as function.
    Donc dans ma tête je me suis dit: les tableaux ça marche avec () et avec [] pour accéder aux éléments, là c'est surement pareil. N'ayant pas d'erreurs, je suis parti du principe que ça marchait mais peut-être pas à cause du pointeur.

    Et je voulais passer un pointeur car j'ai besoin d'utiliser ma fonction avec this pour renvoyer les déterminants 3x3 de la matrice en appelant MaMatrice.determinant()

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    L'opérateur [] n'a qu'un seul argument, du coup, la virgule que tu as mise est l'opérateur virgule qui évalue ses deux arguments dans l'ordre, et vaut la valeur du second.
    M[1, 2] a la même valeur que M[2], si ce n'est que tu as demandé au compilateur d'évaluer 1 pour rien (et qu'il ne l'aura pas fait )

    Sans compter que si M est un pointeur, M[7] est *(M+7).

    On utilise quasiment jamais this, mais *this, et dans ton cas, operator[](7), ou (*this)[]
    Après tout, c'est une fonction membre (non statique), on a this.
    C'est amusant de voir que tu vérifies si la matrice est carrée, mais pas 3x3. Soit tu fais confiance à l'utilisateur, soit tu te méfies, mais il faut choisir.

    Du coup, on ne prend que des références constantes (ou modifiantes si cela a du sens), sauf cas particulier (passage par copie, en général).

    Tu pourrais l'écrire ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    double get(row_type r, col_type c) const {return operator()(r, c);}
     
    double Matrix::Det3x3Matrix() {
        return  get(0, 0) * (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2))
                - get(0, 1) * (get(1, 0) * get(2, 2) - get(2, 0) * get(1, 2))
                + get(0, 2) * (get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1));
    }
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Points : 55
    Points
    55
    Par défaut
    En vérité cette fonction ne sera pas appelée par l'utilisateur mais pas la fonction déterminant car je vais en avoir besoin pour le calculer. Le test si la matrice est 3x3 est faite dans cette fonction.

    En tout cas merci pour l'explication, je vais voir si ça marche.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Avatar36 Voir le message
    les tableaux ça marche avec () et avec [] pour accéder aux éléments,
    Wait, what ?!?!?

    Déjà tu n'as pas une Matrice, mais une Matrice* et les opérateurs ne sont pas surchargés pour un pointeur.
    Plus, l'opérateur [] sur un pointeur fera juste un décallage, c'est ainsi qu'on accède au n-ième élément d'un tableau, qui est aussi un pointeur. Donc certainement pas un operator[] surchargé.
    Enfin, la , (virgule) que tu mets entre les [] n'a surement pas l'effet escompté. L'opérateur , est vicieux, je ne l'utilise jamais et ne suis jamais vraiment sûr de son fonctionnement à vrai dire.
    Et l'erreur est donnée par ton compilo : l'operator() n'existe pas pour une Matrice*, puisque tu l'as défini pour une Matrice... faut déférencer ton pointeur, et/ou mieux ne pas passer un pointeur, à fortiori non constant, à une méthode qui n'en a clairement aucune utilité.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Avatar36 Voir le message
    Et je voulais passer un pointeur car j'ai besoin d'utiliser ma fonction avec this pour renvoyer les déterminants 3x3 de la matrice en appelant MaMatrice.determinant()
    Même quand cela a du sens de transmettre l'objet courant à une fonction (et cela n'en a absolument pas ici, vu que tu appelle une fonction membre de l'objet qui ... connait forcément l'objet courant grâce à this ), il est très largement préférable de "déréférencer" le pointeur this afin de transmettre l'objet courant sous la forme d'une référence (qui pourra en cas de besoin(*) être constante), et cela, pour toute une série de raisons, les principales étant :
    • Un pointeur peut être nul. Il faut donc systématiquement tester si le paramètre obtenu représente une adresse valide avant toute tentative de déréférencement
    • Il est très difficile de respecter la constance des objets avec les pointeurs
    • un pointeur nu risque d'inciter le développeur à invoquer delete dessus si les règles ne sont pas clairement établies
    • l'utilisation des pointeurs nous oblige à adapter la syntaxe, soit en utilisant -> soit en faisant en sorte d'utiliser "ce qui est pointé" par le pointeur (*ptr).
    • Quel que soit l'opérateur que tu essaye d'appeler, c'est systématiquement la m...de le faire au départ d'un pointeur
    • Les référence apportent ne garantie de non nullité : lorsque l'on reçoit un paramètre par référence, il y a forcément un objet référencé
    • Si tu déclares une référence comme étant constante, tu pourras danser sur ta tête : le compilateur refusera tout appel à une fonction qui ne s'engagerait pas à ne pas modifier le paramètres, que ce soit une fonction libre nécessitant une référence non constante sur ce paramètre ou une fonction membre qui n'est pas déclarée constante. La constance est "virale" et cela nous va très bien
    • les références utilisent exactement la même syntaxe que les variables "classiques" et l'on peut appeler n'importe quel opérateur exactement comme s'il s'agissait d'une variable normale
    • j'en oublie surement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Points : 55
    Points
    55
    Par défaut
    En faisant (*this)(ligne, colonne) ça marche. Effectivement, je me suis débarrassé des pointeurs du coup.
    C'est la première fois que je fais une surcharge d'opérateur donc il y a des choses qui m'échappent (je suis pas à l'aise avec les références).
    Et j'ai pris la mauvaise habitude de ne pas mettre de références dans mes fonctions. Je vais lire un peu de doc dessus.

    Merci de votre aide.

    Cordialement

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 09/03/2010, 09h56
  2. Réponses: 3
    Dernier message: 02/03/2010, 08h16
  3. [C#] Tri d'objet et surcharge d'opérateur
    Par Royd938 dans le forum Windows Forms
    Réponses: 6
    Dernier message: 17/12/2007, 00h26
  4. [C#]Comment surcharger l'opérateur [] ?
    Par NicolasJolet dans le forum C#
    Réponses: 11
    Dernier message: 09/04/2006, 12h00
  5. [VB .NET] Surcharge d'opérateur
    Par Franckintosh dans le forum VB.NET
    Réponses: 2
    Dernier message: 07/09/2004, 19h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo