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 :

L'exemple du «dynamic_cast» de la faq ne se compile pas avec g++.


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 9
    Points
    9
    Par défaut L'exemple du «dynamic_cast» de la faq ne se compile pas avec g++.
    Bonjour à tous.
    Je me remets au C++ et j'ai tenté de compiler l'exemple du «dynamic_cast» à l'adresse :
    https://cpp.developpez.com/faq/cpp/?...explicite-cast

    La ligne de commande suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     :-) g++ -g -Wall -o essai essai.cpp
    Me donne comme message d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    essai.cpp: In function ‘int main()’:
    essai.cpp:45:12: warning: unused variable ‘c’ [-Wunused-variable]
            C & c = dynamic_cast<C&>( *a );
                ^
    essai.cpp:48:32: error: expected unqualified-id before ‘&’ token
        catch ( const std::bad_cast & )
                                    ^
    essai.cpp:48:32: error: expected ‘)’ before ‘&’ token
    essai.cpp:48:32: error: expected ‘{’ before ‘&’ token
    essai.cpp:48:34: error: expected primary-expression before ‘)’ token
        catch ( const std::bad_cast & )
    Je n'ai pas trop abordé le sujet des exeptions et c'est pourquoi je pose cette question.

    Sinon, pour la version de g++ :
    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
     
     :-) g++ -v
    Using built-in specs.
    COLLECT_GCC=g++
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
    Target: x86_64-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18+deb9u1' --with-bugurl=file:///
    usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/
    usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --
    libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls -
    -with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-defau
    lt-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugi
    n --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-
    cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=
    /usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --w
    ith-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --en
    able-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,m
    x32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x8
    6_64-linux-gnu --target=x86_64-linux-gnu                                                             
    Thread model: posix
    gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) 
     :-)
    Merci pour votre aide et bonne soirée.

  2. #2
    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 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    L'exemple date, présente des fuites mémoire , et faire un dynamic_cast en utilisant des références est franchement bof, je ne l'ai jamais vu..
    En tous cas, il se plaint qu'il ne connait pas std::bad_cast. As-tu bien inclus typeinfo ? https://en.cppreference.com/w/cpp/types/bad_cast
    L'utilisation de dynamic_cast est assez faible dans un projet réel correctement architecturé.
    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.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 9
    Points
    9
    Par défaut
    Merci pour ton aide efficace. Dans l'exemple, il manque effectivement «typeinfo». en ajoutant à la fin des includes :
    ça se compile sans problème.

    J'ai pris bonne note du site «cppreference.com/», il semble vraiment précieux.

    En ce qui concerne la fuite de mémoire, cinq «new» sans aucun «delete» à la suite, ça semble quelque peu rock'n' roll…
    Alors, je propose le correctif suivant :
    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
    #include <iostream> 
    #include <string> 
    #include <typeinfo>
     
    class A 
    { 
    public: 
      virtual std::string get_type() = 0; 
      virtual ~A(){std::cout << "virtual ~A()" << std::endl ;} ;
    }; 
     
    class B : public A 
    { 
    public: 
      virtual std::string get_type() { return "B"; } 
      virtual ~B(){std::cout << "virtual ~B()" << std::endl ;} ;
    }; 
     
    class C : public A 
    { 
    public: 
      virtual std::string get_type() { return "C"; }; 
      virtual ~C(){std::cout << "virtual ~C()" << std::endl ;} ;
    }; 
     
    A * create_B_or_C() 
    { 
      static int nb = 0; 
      // si nb est pair, on crée un B, sinon un C 
      ++nb; 
      if ( nb % 2 == 0 ) { return new B; } 
      return new C; 
    } 
     
    int main() 
    { 
      for ( int i = 0; i < 5; ++i ) 
        { 
          A *a = create_B_or_C(); 
          std::cout << "Test sur un " << a->get_type() << " : "; 
     
          B *b = dynamic_cast<B*>( a ); 
          if ( b == 0 ) 
            { 
    	  // échec du cast en B, il doit s'agir d'un C 
    	  // lève std::bad_cast s'il ne s'agit pas d'un C 
    	  try 
                { 
    	      C &c = dynamic_cast<C&>( *a ); 
    	      std::cout << "il s'agit d'un C.\n"; 
    	      delete &c ;
                } 
    	  catch ( const std::bad_cast & ) 
                { 
    	      std::cout << "Oups!\n"; 
                } 
            } 
          else 
            { 
    	  std::cout << "il s'agit d'un B.\n"; 
    	  delete b ;
            }
        }
    }
    Qu'en pensez vous?

  4. #4
    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 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Le plus simple est de faire un delete a; en fin de boucle.
    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.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Peut-être y rajouter un commentaire qui mentionne que le delete a; est valide parce que le destructeur est virtuel.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  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 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Ce point est traité dans 2 autres entrées de FAQ
    - https://cpp.developpez.com/faq/cpp/?...ucteur-virtuel
    - https://cpp.developpez.com/faq/cpp/?...et-non-virtuel
    Le but de la FAQ est normalement d'avoir des entrées simples sur 1 point unique - ce qui est déjà peu le cas, la FAQ est vieille et loin d'être à jour. Pas d'être un mini-article qui détaille toutes les possibilités.
    Sinon il faudrait aussi expliquer ce qu'est une référence, que se passe-t-il en cas d'exception, présenter un meilleur exemple avec un unique_ptr, expliquer que le dynamic_cast ne devrait pas être utilisé et présenter comment faire autrement, ... et t'en finis jamais.
    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
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Le plus simple est de faire un delete a; en fin de boucle.
    Ha! L'erreur typique du débutant qui a du mal à se mettre en tête qu'un pointeur n'est pas un objet, mais un «point de vue» sur ce dernier…
    Bon, une fois rectifié, cela donne :
    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
    #include <iostream> 
    #include <string> 
    #include <typeinfo>
     
    class A 
    { 
    public: 
      virtual std::string get_type() = 0; 
      virtual ~A(){std::cout << "virtual ~A()" << std::endl ;} ;
    }; 
     
    class B : public A 
    { 
    public: 
      virtual std::string get_type() { return "B"; } 
      virtual ~B(){std::cout << "virtual ~B()" << std::endl ;} ;
    }; 
     
    class C : public A 
    { 
    public: 
      virtual std::string get_type() { return "C"; }; 
      virtual ~C(){std::cout << "virtual ~C()" << std::endl ;} ;
    }; 
     
    A * create_B_or_C() 
    { 
      static int nb = 0; 
      // si nb est pair, on crée un B, sinon un C 
      ++nb; 
      if ( nb % 2 == 0 ) { return new B; } 
      return new C; 
    } 
     
    int main() 
    { 
      for ( int i = 0; i < 5; ++i ) 
        { 
          A *a = create_B_or_C(); 
          std::cout << "Test sur un " << a->get_type() << " : "; 
     
          B *b = dynamic_cast<B*>( a ); 
          if ( b == 0 ) 
            { 
    	  // échec du cast en B, il doit s'agir d'un C 
    	  // lève std::bad_cast s'il ne s'agit pas d'un C 
    	  try 
                { 
    	      C &c = dynamic_cast<C&>( *a ); 
    	      std::cout << "il s'agit d'un C.\n"; 
                } 
    	  catch ( const std::bad_cast & ) 
                { 
    	      std::cout << "Oups!\n"; 
                } 
            } 
          else 
            { 
    	  std::cout << "il s'agit d'un B.\n"; 
            }
          delete a ;
        }
    }
    Citation Envoyé par Médinoc Voir le message
    Peut-être y rajouter un commentaire qui mentionne que le delete a; est valide parce que le destructeur est virtuel.
    De toutes façons, des destructeurs non virtuels avec l'héritage, c'est beurk non?

  8. #8
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    L'exemple semble avoir été mis à jour. Merci à lui.

    Ce qui suit, n'apporte pas grand chose à la discussion, mais je le mentionne, dans un but d'amélioration de la FAQ.
    Je vois que le pointeur b est comparé à 0. Pourquoi ne pas le comparer avec NULL ou encore mieux, nullptr ?

    Quid d'ajouter le destructeur virtuel ? (en plus, c'est un warning G++)
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 9
    Points
    9
    Par défaut
    Bonjour,
    au risque de paraître quel peu pénible, il me semble qu'il y a un problème avec la nouvelle version de la FAQ.
    J'ai compilé l'exemple et j'ai un warning supplémentaire au sujet du «delete» de l'objet pointé par «a».
    J'ai remis des marqueurs sur les destructeurs et ça me donne :
    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
     :-) g++ -g -Wall -o dynamic_cast dynamic_cast-nouvelle_version.cpp && ./dynamic_cast
    dynamic_cast-nouvelle_version.cpp: In function ‘int main()’:
    dynamic_cast-nouvelle_version.cpp:49:12: warning: unused variable ‘c’ [-Wunused-variable]
            C & c = dynamic_cast<C&>( *a );
                ^
    dynamic_cast-nouvelle_version.cpp:61:14: warning: deleting object of abstract class type ‘A’ which has
     non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]
           delete a;
                  ^
    Test sur un C : il s'agit d'un C.
    ~A()
    Test sur un B : il s'agit d'un B.
    ~A()
    Test sur un C : il s'agit d'un C.
    ~A()
    Test sur un B : il s'agit d'un B.
    ~A()
    Test sur un C : il s'agit d'un C.
    ~A()
     :-)
    Il semble que le destructeur de l'objet dérivé ne soit pas appelé… Et si ce dernier aussi allouais de la mémoire, sur le tas par exemple…
    N'y aurait il pas là un problème?

    Ci-dessous le code compilé :
    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
    #include <iostream> 
    #include <string> 
    #include <typeinfo> 
     
    class A 
    { 
    public: 
      virtual std::string get_type() = 0; 
      ~A(){std::cout << "~A()" << std::endl ;} ;
    }; 
     
    class B : public A 
    { 
    public: 
      virtual std::string get_type() { return "B"; } 
      ~B(){std::cout << "~B()" << std::endl ;} ;
    }; 
     
    class C : public A 
    { 
    public: 
      virtual std::string get_type() { return "C"; }; 
      ~C(){std::cout << "~C()" << std::endl ;} ;
    }; 
     
    A * create_B_or_C() 
    { 
      static int nb = 0; 
      // si nb est pair, on crée un B, sinon un C 
      ++nb; 
      if ( nb % 2 == 0 ) { return new B; } 
      return new C; 
    } 
     
    int main() 
    { 
      for ( int i = 0; i < 5; ++i ) 
        { 
          A *a = create_B_or_C(); 
          std::cout << "Test sur un " << a->get_type() << " : "; 
     
          B *b = dynamic_cast<B*>( a ); 
          if ( b == 0 ) 
            { 
    	  // échec du cast en B, il doit s'agir d'un C 
    	  // lève std::bad_cast s'il ne s'agit pas d'un C 
    	  try 
                { 
    	      C & c = dynamic_cast<C&>( *a ); 
    	      std::cout << "il s'agit d'un C.\n"; 
                } 
    	  catch ( const std::bad_cast & ) 
                { 
    	      std::cout << "Oups!\n"; 
                } 
            } 
          else 
            { 
    	  std::cout << "il s'agit d'un B.\n"; 
            } 
          delete a; 
        } 
    }

  10. #10
    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 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    L'entrée de FAQ est là pour présenter le dynamic_cast, pas pour être un cours sur l'héritage, le mot-clé virtual etc.
    Étant une entrée de FAQ, que le delete ne soit pas présent et qu'il y ait une fuite ne me choquerait pas.
    C'est même ce pour quoi je plaiderais pour ne pas avoir à corriger ou expliquer 600 warning ou erreurs.
    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.

  11. #11
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Moi, je trouve qu'un code trouvé sur une ressource, doit être le plus propre possible (donc qu'il y ait les delete, les virtual...). Dans le cas contraire, un débutant pourrait croire que c'est ainsi que l'on code dans la "vraie vie" et prendre le code de la FAQ comme référence.

    Maintenant, on peut aussi se dire que l'exemple est à améliorer/revoir complètement, car ne focus pas assez sur le concept abordé.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  12. #12
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 25
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Moi, je trouve qu'un code trouvé sur une ressource, doit être le plus propre possible (donc qu'il y ait les delete, les virtual...). Dans le cas contraire, un débutant pourrait croire que c'est ainsi que l'on code dans la "vraie vie" et prendre le code de la FAQ comme référence.

    Maintenant, on peut aussi se dire que l'exemple est à améliorer/revoir complètement, car ne focus pas assez sur le concept abordé.
    Exact, et je pense que les mauvaises habitudes ont la vie dure…

    Ceci dit, merci pour votre aide!

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

Discussions similaires

  1. Son ne fonctione pas avec un exemple de la FAQ ?
    Par [ZiP] dans le forum Débuter
    Réponses: 7
    Dernier message: 01/09/2009, 14h24
  2. L'exemple des thread de la FAQ ne marche pa chez moi
    Par mcdonald dans le forum Général Python
    Réponses: 2
    Dernier message: 10/06/2006, 14h47
  3. Precisions sur le dynamic_cast de la FAQ
    Par Klaim dans le forum C++
    Réponses: 3
    Dernier message: 09/02/2006, 00h18
  4. La FAQ qui ne marche pas mais pourquoi?
    Par Antoine_1977 dans le forum Access
    Réponses: 3
    Dernier message: 27/09/2005, 16h22

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