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 :

Exceptions, héritage et méthodes virtuelles


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut Exceptions, héritage et méthodes virtuelles
    Bonjour,

    Cela fait plusieurs heures que je bloque sur le problème suivant. Voici mon bout de code de test de l'architecture des exceptions pour mon projet :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    #include <iostream>
    #include <string>
     
    using namespace std;
     
    // Classe de base des exceptions
    class Exception {
    public :
        Exception() : next(NULL) {}
        Exception& add(Exception& e) {
            Exception* tmp = this;
            while (tmp->next != NULL)
                tmp = tmp->next;
            tmp->next = &e; 
            return *this;
        }
        virtual string show() { return "Classe Exception"; }
        Exception* next;
    };
     
    // Première exception
    class ExceptionA : public Exception {
    public:
        virtual std::string show() { return "Classe ExceptionA"; }
    };
     
    // Seconde exception
    class ExceptionB : public Exception {
    public:
        virtual std::string show() { return "Classe ExceptionB"; }
    };
     
    // Affichage;
    ostream& operator<<(ostream& out, Exception& e) {
        out << e.show() << endl;
        if (e.next != NULL)
            out << *e.next;
        return out;
    }
     
    int main(int argc, char *argv[])
    {
        // Test d'une exception basique
        try {
            throw ExceptionA();
        } catch (Exception& e) {
            // On attend l'affichage :
            // Class ExceptionA
            cout << "Test simple :" << endl << e << endl;
        }
     
        // Test d'une exception en cascade n°1
        try {
            try {
                throw ExceptionA();
            } catch (Exception& e) {
                ExceptionB b = ExceptionB();
                b.add(e);
                throw b;
            }
        } catch (Exception& e) {
            // On attend l'affichage :
            // Class ExceptionB
            // Class ExceptionA
            cout << "Test cascade n°1 :" << endl << e << endl;
        }
     
        // Test d'une exception en cascade n°2
        try {
            try {
                throw ExceptionA();
            } catch (Exception& e) {
                throw ExceptionB().add(e);
            }
        } catch (Exception& e) {
            // On attend l'affichage :
            // Class ExceptionB
            // Class ExceptionA
            cout << "Test cascade n°2 :" << endl << e << endl;
        }
     
        return 0;
    }
    Comme vous l'aurez probablement affiché il "foire" au test en cascade n°2 et m'affiche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Test cascade n°2 :
    Classe Exception
    Classe ExceptionA
    Vous avez une idée de la raison pour laquelle cela ne fait pas du tout ce que j'attends ? De plus la classe Exception ne sera jamais instanciée, je voulais en faire une classe abstraitre mais cela ne fonctionne pas avec l'envoi d'exceptions :/ c'est la raison pour laquelle j'ai défini la méthode Exception::show()

    Merci beaucoup de votre aide.

    Nuwanda

  2. #2
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Nuwanda
    Vous avez une idée de la raison pour laquelle cela ne fait pas du tout ce que j'attends?
    L'objet jete est copie avant d'etre passe au catch. Et la copie se fait avec le type statique de l'objet jete. Le type statique de
    c'est le type du resultat de add(), donc Exception.
    De plus la classe Exception ne sera jamais instanciée, je voulais en faire une classe abstraitre mais cela ne fonctionne pas avec l'envoi d'exceptions :/
    Meme cause. La copie generee ci-dessus est une instantiation.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut
    Merci beaucoup. J'ai mis un moment à comprendre, mais avec quelques affichage d'addresses mémoire et 2-3 tests j'ai compris pourquoi cela foire. C'est donc le throw qui copie l'objet.

    Si l'objet est copié quelle est l'utilité d'avoir le "&" dans le catch ? Vu que l'on ne manipule pas l'objet lancé ?!?!? Donc si on ne met pas le "&" on copie deux fois l'objet ?

    Y'a-t-il un moyen de contourner ce problème ? Peut-être en rusant avec le constructeur par copie (mais c'est juste une hypothèse, je ne maitrise pas vraiment ce domaine) ?

  4. #4
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    en effet, à priori, si on ne mets pas le & dans le catch, il y a deux copies...

    pour ce qui est de ruser... le seul moyen que je vois semble être de lever en fait un pointeur, alloué avec new, mais c'est pas terrible : il faut le delete, et en plus, c'est même pas sûr qu'un Exception* catch un ExceptionB*
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag (en bas)

  5. #5
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Nuwanda
    Si l'objet est copié quelle est l'utilité d'avoir le "&" dans le catch ?
    Ne pas copier une deuxieme fois, ce qui dans le cas present tronquerait tous les objets lances a leur type de base, Exception.

    Y'a-t-il un moyen de contourner ce problème ? Peut-être en rusant avec le constructeur par copie (mais c'est juste une hypothèse, je ne maitrise pas vraiment ce domaine) ?
    Tu veux un comportement polymorphe en meme temps qu'une semantique de copie. Donc il faut jeter un pointeur, eventuellement encapsule pour s'assurer de sa destruction a bon escient.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  6. #6
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Swoög
    c'est même pas sûr qu'un Exception* catch un ExceptionB*
    Si.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  7. #7
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Si.
    OK, merci beaucoup
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag (en bas)

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut
    Donc, je viens de faire 2-3 tests...

    Si j'ajoute la constructeur par copie dans la classe Exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        Exception(const Exception& e) { cout << "Copie de l'objet " << &e << " dans " << this << endl; }
    J'obtiens 2 choses intéressantes :
    - Quand on ne met pas le "&" dans le catch, on a bien deux copies. (mais c'est pas le plus bizarre)
    - Il ne m'affiche que la première exception et pas celle ajoutée à la suite ?!?!?

  9. #9
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Nuwanda
    J'obtiens 2 choses intéressantes :
    - Quand on ne met pas le "&" dans le catch, on a bien deux copies. (mais c'est pas le plus bizarre)
    C'est pas bizarre, c'est attendu.

    - Il ne m'affiche que la première exception et pas celle ajoutée à la suite ?!?!?
    Et le champs next, il est initialise comment? J'ai comme l'impression que par chance il contient un pointeur nul.

    Au fait, il manque le clean up de ce qui est alloue dynamiquement.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut
    Merci beaucoup de votre aide à tous, j'ai résolu mon problème en utilisant des pointeurs, ca fonctionne maintenant exactement comme je le souhaite.

    Voici le code correspondant :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    #include <iostream>
    #include <string>
     
    using namespace std;
     
    // Classe de base des exceptions
    class Exception {
    public :
        Exception() : next(NULL) {}
        Exception* add(Exception* e) {
            Exception* tmp = this;
            while (tmp->next != NULL)
                tmp = tmp->next;
            tmp->next = e; 
            return this;
        }
        virtual string show() { return "Classe Exception"; }
        Exception* next;
    };
     
    // Première exception
    class ExceptionA : public Exception {
    public:
        virtual string show() { return "Classe ExceptionA"; }
    };
     
    // Seconde exception
    class ExceptionB : public Exception {
    public:
        virtual string show() { return "Classe ExceptionB"; }
    };
     
    // Affichage;
    ostream& operator<<(ostream& out, Exception* e) {
        out << e->show() << endl;
        if (e->next != NULL)
            out << e->next;
        return out;
    }
     
    int main(int argc, char *argv[])
    {
        // Test d'une exception basique
        try {
            throw new ExceptionA();
        } catch (Exception*& e) {
            // On attend l'affichage :
            // Class ExceptionA
            cout << "Test simple :" << endl << e << endl;
        }
     
        // Test d'une exception en cascade n°1
        try {
            try {
                throw new ExceptionA();
            } catch (Exception* e) {
                ExceptionB* b = new ExceptionB();
                b->add(e);
                throw b;
            }
        } catch (Exception* e) {
            // On attend l'affichage :
            // Class ExceptionB
            // Class ExceptionA
            cout << "Test cascade n°1 :" << endl << e << endl;
        }
     
        // Test d'une exception en cascade n°2
        try {
            try {
                throw new ExceptionA();
            } catch (Exception* e) {
                throw (new ExceptionB())->add(e);
            }
        } catch (Exception* e) {
            // On attend l'affichage :
            // Class ExceptionB
            // Class ExceptionA
            cout << "Test cascade n°2 :" << endl << e << endl;
        }
     
        return 0;
    }
    Question subsidiaire : Pourquoi il se mélange les pinceaux entre type réel et type déclaré quand j'utilise les objet, mais quand j'utilise les pointeurs sur objet, il s'en sort parfaitement ?

  11. #11
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    parce qu'il fait une copie de pointeur, c'est à dire qu'il copie "la valeur de l'adresse"

    alors que sinon, il copie la valeur de l'objet avec le type courant (dans ce cas Expression puisque ta fonction renvoie un Expression&
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag (en bas)

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut
    Merci beaucoup !

  13. #13
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Nuwanda
    Merci beaucoup de votre aide à tous, j'ai résolu mon problème en utilisant des pointeurs, ca fonctionne maintenant exactement comme je le souhaite.

    Voici le code correspondant :
    Il a encore des problemes:
    1. il se fie au constructeur de copie, a l'operateur d'assignement et au destructeur par defaut pour une classe (Exception) ayant un membre pointeur; ce n'est generalement pas une bonne idee car on ne sait pas qui doit liberer ce pointeur. Dans les rares cas ou c'est adapte, je conseille de mettre un commentaire indiquant que c'est voulu.
    2. il y a des allocations de memoire sans liberation (probleme en partie lie au premier mais plus generalement, il n'a pas l'air d'avoir eu de reflexion sur ce probleme).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 47
    Points : 22
    Points
    22
    Par défaut
    Bonjour,

    Tout d'abord, je vous remercie de votre interêt pour mon projet ainsi que des éventuels problèmes que je vais renconter.

    Il faut savoir que les exceptions qui sont lancées doivent arrêter le logiciel. En effet, je fais un traitement sur des données, si le fichier de données contient des erreurs, je ne peux continuer.

    Je dois avouer que pour le moment, ma préocuppation n'est pas de savoir qui doit libérer la mémoire vu que le projet DOIT s'arrêter en cas d'erreur. Je laisse le soin à l'OS de faire la libération de mémoire (il s'agit bien évidemment d'une solution temporaire). Pour le moment, étant donné que le traitement sera très long (plusieurs jours), je me préocuppe principalement de vérifier que l'espace mémoire ne gonfle pas lors du traitement.

    Pour la libération de la mémoire des exceptions lorsque celles ci sont reliées, chaque exception supprime la suivante. Théoriquement le code suivant fonctionne comme je le souhaite (enfin j'espère...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Exception::~Exception()
    {
        delete next;
    }
    S'il n'y a pas de suivant, next est à NULL, donc cela s'arrête. De plus le destructeur est virtuel.

    Sinon lorsque je vais développer la libération de mémoire, mes données ont une structure arborescente qui fait que chaque élement se chargera de supprimer les suivants et ainsi de suite. J'espère un joli fonctionnement en cascade. Ma seule crainte en réalité vient de la librairie que j'utilise et j'espère qu'elle n'a pas trop de fuites mémoires...

    Bonne journée !

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

Discussions similaires

  1. méthode virtuelle dans héritages
    Par bobby51 dans le forum Langage
    Réponses: 4
    Dernier message: 21/02/2010, 19h36
  2. héritage et méthode virtuelle
    Par cibatro dans le forum Langage
    Réponses: 11
    Dernier message: 28/07/2009, 17h13
  3. méthode virtuelle pure et héritage
    Par Invité dans le forum Langage
    Réponses: 3
    Dernier message: 20/07/2009, 22h12
  4. héritage et méthodes virtuelles ?
    Par Didine981 dans le forum C++
    Réponses: 4
    Dernier message: 08/12/2007, 13h43
  5. [Héritage] Downcasting et méthodes virtuelles
    Par poukill dans le forum C++
    Réponses: 8
    Dernier message: 16/07/2007, 13h38

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