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 :

Liste et objets polymorphes


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Par défaut Liste et objets polymorphes
    Bonjour,

    Plutôt qu'un long discours voici un exemple de ma problématique :
    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
    #include <iostream>
    #include <stdlib.h>
    #include <list>
     
    using namespace std;
     
    struct Base
    {
    	virtual string foo() const { return "Base"; }
    };
     
    struct Derived : public Base
    {
    	string foo() const { return "Derived"; }
    };
     
    void bar(const list<Base*>& myList)
    {
    	const Base* element;
     
    	for (list<Base*>::const_iterator it = myList.begin(); it != myList.end(); it++)
    	{
    		element = (const Base*)*it;
    		cout << element->foo() << endl;
    	}
     
    	cout << endl;
    }
     
    int main()
    {
    	Base base;
    	Derived derived;
    	Base& baseDerived = derived;
     
    	list<Base*> baseList;
    		baseList.push_back(&base);
    		baseList.push_back(&derived);
    		baseList.push_back(&baseDerived);
     
    	list<Derived*> derivedList;
    		derivedList.push_back(&derived);
     
    	cout << "--- baseList : " << endl;
    	bar(baseList);
     
    	cout << "--- derivedList : " << endl;
    	bar(derivedList); // Ne compile pas
     
    	return EXIT_SUCCESS;
    }
    Comme vous pouvez le voir, l'avant dernière ligne ne compile pas, car les types ne correspondent pas.
    Je pourrais bien entendu passer par une fonction template mais dans ce cas je perds l'intérêt du typage et n'ai plus la garantie que les objets de la liste possèdent bien une méthode "foo()"...

    Je voudrais donc savoir si je m'y prends mal ou s'il y a une manière d'obtenir un résultat similaire en profitant des avantages du typage.


    Dans mon cas concret j'ai une classe abstraite XmlObject, elle contient deux méthodes virtuelles pures pour charger et écrire un objet en XML.
    Bien sûre je n'ai jamais un seul objet du même type, je les stock donc dans des listes.

    J'aurais donc voulu pouvoir faire une méthode statique donc le prototype serait du genre :
    void fromXml(std::list<XmlInterface*>& list, const std::string& filePath);

    Mais comme on le constate dans l'exemple épuré ci-dessus, cela ne fonctionne pas...

    Merci de votre aide, bonne journée.

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    un problème similaire a été posé il y a peu.

    un vector<Base*> peut contenir toute classe dérivant de Base*, mais ne peut pas être traité comme un vector<Derived*>, et inversement.

    je perds l'intérêt du typage et n'ai plus la garantie que les objets de la liste possèdent bien une méthode "foo()"...
    Si ton seul souci est d'avoir la méthode foo disponible, la compilation échouera si elle n'existe pas. Donc non tu ne perds aucune garantie.
    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
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Par défaut
    Ok, merci quand même.

    Pour la compilation je pensais bien mais je me demandais si dans certains cas, où le compilateur ne saurais qu'à l’exécution le type d'un objet, si ça ne pouvais pas poser problème.

    Au début je pensais surtout à un problème de constructeur, peut-être une façon explicite de dire au compilateur qu'un objet Base peut être construit à partir d'un objet Derived et la conversion des éléments de la liste serait faite implicitement...
    On peut toujours espérer

    Bonne continuation.

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour

    Tu peux quand même utiliser un paramètre template pour accepter les différentes classes et utiliser type_traits pour vérifier que le type passé en paramètre soit bien une classe dérivée de Base avec std::is_base_of

    Hors sujet : je te conseille de faire comme les algos de la STL et de passer une paire d'itérateurs plutôt qu'un conteneur, tu gagneras en souplesse (pas besoin de modifier le code si tu veux changer de conteneur)

    De plus (à voir avec ton vrai code, celui donné en exemple s'y prête bien), utilise directement les algo de la STL avec une lambda (dispo depuis plusieurs années avec gcc)

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Par défaut
    Salut,

    Merci pour les propositions, j'aurais quelques questions.

    Hors sujet : je te conseille de faire comme les algos de la STL et de passer une paire d'itérateurs plutôt qu'un conteneur, tu gagneras en souplesse (pas besoin de modifier le code si tu veux changer de conteneur)
    Tu entends par là passer un couple d'itérateurs représentants le premier et dernier élément du conteneur que je veux passer en paramètres ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void bar(const list<Base*>::const_iterator begin, list<Base*>::constçiterator end) const;
     
    // Appelé ainsi :
    bar(baseList.begin(), baseList.end());

    De plus (à voir avec ton vrai code, celui donné en exemple s'y prête bien), utilise directement les algo de la STL avec une lambda (dispo depuis plusieurs années avec gcc)
    Je viens de regarder rapidement car je ne connais pas les lambda, ce sont les "fonctions" du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [] (Type paramName) { /* Instructions */ }
    Si oui, qu'elle est la différence avec les foncteurs ?

    j'ai la version 4.6.1 de gcc qui me demande de compiler avec l'option -std=c++0x pour pouvoir utiliser les lambdas, malheureusement j'ai une belle flopée d'erreurs qui apparaît :
    undefined reference to `std::cout'
    Et autres joyeusetés du même genre, je regarderais plus tard après avoir compris la différence avec les foncteurs.

    Encore merci pour ces informations, bonne journée.

  6. #6
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Oui, l'utilisation des itérateurs sera plus simple et indépendante du type de container en amont.

    Pour les lambdas, c'est exactement comme les foncteurs mais plus rapide et simple à écrire/maintenir (la définition de la lambda est le plus souvent là où on l'utilise, c'est moins lourd que de devoir déclarer un foncteur).
    Mais nécessite C++11.
    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
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Citation Envoyé par the_angel Voir le message
    j'ai la version 4.6.1 de gcc qui me demande de compiler avec l'option -std=c++0x pour pouvoir utiliser les lambdas, malheureusement j'ai une belle flopée d'erreurs qui apparaît :
    undefined reference to `std::cout'
    Et autres joyeusetés du même genre, je regarderais plus tard après avoir compris la différence avec les foncteurs.
    étrange comme erreur. Pour les lambdas, pas de problème, gcc prend en charge depuis 4.5. Pour std::cout (comme tu dois t'en doutais), ça n'a pas été enlevé dans le C++11 Peut être un conflit avec les anciens fichiers .o
    Supprime tous ces fichiers et recompile tout pour voir

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par the_angel Voir le message
    j'ai la version 4.6.1 de gcc qui me demande de compiler avec l'option -std=c++0x pour pouvoir utiliser les lambdas, malheureusement j'ai une belle flopée d'erreurs qui apparaît :
    undefined reference to `std::cout'
    Et autres joyeusetés du même genre, je regarderais plus tard après avoir compris la différence avec les foncteurs.

    Encore merci pour ces informations, bonne journée.
    Je me demande si tu n'effectue pas l'édition de lien avec gcc au lieu de la faire avec g++...

    C'est une cause courante qui occasionne les "undefined reference to <somehting from std>"

    En effet, gcc effectue l'édition de liens avec, par défaut, les bibliothèques C uniquement, alors que g++ rajoute automatiquement les flags nécessaires à l'utilisation des bibliothèques C++.

    Il n'est donc pas impossible, avec un code aussi simple que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include <iostream>
    int main()
    {
        std::cout<<"hello world"<<std::endl;
        return 0;
    }
    que gcc -o test main.ote sorte une erreur d'édition de liens (référence indéfinie sur std::cout) alors que
    g++ -o test main.o fonctionne sans problème


    Les flags à rajouter éventuellement pour permettre à la commande gcc -o test main.o de compiler correctement ressemblent sans doute à quelque chose comme
    gcc -o test main.o -lstdc++

    Penses aussi à t'assurer que le .lib se trouve dans un dossier dans lequel le compilateur cherche déjà après les différentes bibliothèques
    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

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

Discussions similaires

  1. Liste d'objets et STL
    Par thibouille dans le forum SL & STL
    Réponses: 2
    Dernier message: 23/10/2005, 17h41
  2. Tri d'une liste d'objet CObList
    Par cjacquel dans le forum MFC
    Réponses: 1
    Dernier message: 13/07/2005, 13h50
  3. [MFC] Retourner une liste d'objets
    Par 1cado dans le forum MFC
    Réponses: 10
    Dernier message: 28/07/2003, 12h11
  4. [Kylix] Composant - Liste d'objet
    Par Metal3d dans le forum EDI
    Réponses: 1
    Dernier message: 13/12/2002, 22h17
  5. liste d'objets
    Par Pierrot dans le forum Langage
    Réponses: 2
    Dernier message: 27/09/2002, 09h56

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