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 :

Héritage: constructeur par copie de classe héritantes


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Octobre 2004
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 15
    Points : 16
    Points
    16
    Par défaut Héritage: constructeur par copie de classe héritantes
    Bien j'ai une classe mère (Vehicule) ayant plusieurs type de classe fille (Moto, Voiture).
    J'ai également une classe ListeVehicules qui est un vecteur de Moto et de Voiture casté en objet Vehicule.

    J'aimerais faire un constructeur de la classe ListeVehicules qui recoit comme paramèttre un vector<Vehicule*>.
    Pour cela, je ne sais pas ce qui est le mieux de faire:
    - passer en boucle sur chaque objet du vecteur;
    - pour chaque objet appeler le constructeur par copie entre deux objets Vehicule
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ListeVehicules::ListeVehicules(vector<Vehicule*> ve)
    {
        this->listeV.resize(ve.size());
        for (unsigned int cpt = 0; cpt < ve.size(); cpt ++)
        {
            this->listeV[cpt] = ve[cpt];
        }
    }
    Ou bien appeler spécifiquement le constructeur de copie des classes filles ?
    - passer en boucle sur chaque objet du vecteur;
    - tester le type d'objet fille
    - en fonction du type appeler le constructeur 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
     
    ListeVehicules::ListeVehicules(vector<Vehicule*> ve)
    {
        this->listeV.resize(ve.size());
        for (unsigned int cpt = 0; cpt < ve.size(); cpt ++)
        {
            // getType retourne 1 pour moto, 2 pour Voiture
            switch (ve[cpt]->getType()) 
            {
                case 1:
                {
                    this->listeV[cpt] = (Vehicule*) new Moto(*ve[cpt]);
                    break;
                }
                case 2:
                {
                    this->listeV[cpt] = (Vehicule*) new Voiture(*ve[cpt]);
                    break;
                }
            }
         }
    }
    Est-ce que la première méthode fera d'elle même appel au constructeur de la classe fille correspondant à l'objet?
    Ou bien suis-je obligé de tester le type et appeler les constructeurs spécifiques moi même ?

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Je trouve tout d'abord étrange que tu veuilles caster tes motos et voitures en véhicules. Ne sont ils pas bien tels qu'ils sont, et ne peux tu te contenter de manipuler des pointeurs ?

    Autrement, pour ton problème, on peut utiliser l'idiome du "constructeur virtuel" (qui n'est pas un constructeur) :
    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
     
    struct Vehicule
    {
      virtual Vehicule *clone() = 0;
    };
     
    struct Voiture : Vehicule
    {
      virtual Voiture *clone(){return new Voiture(*this);}
      // Avec certain mauvais compilos, le type de retour doit être Vehicule*
      // ce qui n'est pas grave, car c'est le type dont on a généralement besoin.
    }
     
    struct Moto : Vehicule
    {
      virtual Moto *clone(){return new Moto(*this);}
    }
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre à l'essai
    Inscrit en
    Octobre 2004
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 15
    Points : 16
    Points
    16
    Par défaut
    Je caste mes motos et voitures uniquement pour pouvoir les mettre dans un même vecteur.

    Pourquoi ne pas utilisé 2vecteurs alors(un pour voiture et un pour moto)?
    Je me suis limité à deux classe filles pour l'exemple; en réalité j'en ai bien plus. Et donc avoir 6vecteurs ca devient bof, ... surtt qu'il risque qu'il ai certain de ces vecteurs qui ne soient pas ou peu utilisé. Et une autre raison est qu'il serait possible qu'il y ai de nouveaux types d'objet fille par la suite. Il est plus simple de rajouter uniquement une classe fille que de devoir en plus aller rajouter des nouveaux vecteurs un peu partt dans le reste du code.

    Pour la méthode clone() c'est une bonne idée, ... Mais avant de mettre ca en place je voulais quand meme savoir si aucune de mes deux méthodes précentées ci-dessus n'execute correctement se que je souhaite ?

    Merci en tt cas.

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Je caste mes motos et voitures uniquement pour pouvoir les mettre dans un même vecteur.
    Règle n°1 : ne pas utiliser les casts C, à part si on travaille avec des entiers
    Règle n°2 : ne pas caster quand cela n'est pas nécessaire.

    Une Voiture est un Vehicule, donc naturellement un Voiture* est implicitement convertible vers Vehicule*...

    Ensuite, si ton conteneur doit contenir des Vehicules de manière polymorphe, ton système n'est pas exception-safe ni vraiment adapté.
    Tu ferais mieux d'envelopper tes pointeurs ou alors d'utiliser des conteneurs pour pointeurs.
    Boost ftw

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par XeN-Lo
    Je caste mes motos et voitures uniquement pour pouvoir les mettre dans un même vecteur.
    En fait, j'ai l'impression que dans ton code, tu ne les cast pas... Quel est le type de ListeVehicules::listeV ? Tu ne l'indiques pas, mais d'après l'usage que tu en montre, il semble qu'il s'agisse d'un vector<Vehicule*>. Si tel est bien le cas (ce qui est un des usages classiques de polymorphisme pour avoir des collections hétérogènes), alors tu ne fais pas de cast de Voiture en Vehicule. Tu fais juste un cast (implicite) de Voiture* en Vehicule*. Ce qui n'a rien à voir !

    Caster de Voiture en Vehicule crée un nouvel objet de type Vehicule, issu de la voiture pour lequel on a supprimer toutes les données membre qui étaient définies au niveau Voiture. On appelle ça du slicing, et c'est très rarement une chose souhaitée.
    Caster de Voiture* vers Vehicule* ne change pas l'objet lui même, et indique seulement que (hors cast dans l'autre sens) on va se restreindre à l'interface publique de Vehicule pour manipuler notre Voiture.


    Citation Envoyé par XeN-Lo
    Pour la méthode clone() c'est une bonne idée, ... Mais avant de mettre ca en place je voulais quand meme savoir si aucune de mes deux méthodes précentées ci-dessus n'execute correctement se que je souhaite ?
    Je me place dans l'hypothèse où tu as bien un vecteur de pointeurs. Les deux méthodes sont radicalement différentes en terme de propriété des pointeurs. La question est qui devra détruire les objets pointés.

    Dans le premier cas, les objets pointés sont connus de ton vecteur, mais aussi du code qui a appelé ta fonction. Qui a donc la responsabilité de les effacer ? Ca dépend de ce que tu veux. Ca peut être le code appelant (qui aurait juste "prêté" ces données à ta classe), ça peut être ta classe (il y aurait eu transfert de propriété), ca peut être plus complexe.

    Dans le second cas, Tu crées de nouveaux objets. Tu en est propriétaire, et le code appelant est propriétaire des siens. Ca clarifie les choses (au prix d'une dulplication d'objets, qui peut être non souhaitée en terme de sémentique sur tes objets. Par exemple faire avancer un véhicule du code appelant ne fera pas avancer le véhicule correspondant dans ta liste, puisqu'ils sont devenus différents).

    Si ce que tu veux est le second cas, ma méthode clone est sémentiquement équivalente, mais plus générique. Avec ta méthode, à chaque endroit où l'on doit dupliquer un objet, on doit connaître tous les types dérivés. Avec la mienne, cette connaissance est centralisée dans les classes, et ajouter une nouvelle classe dérivée ne demandera pas de modifier plein de switch. A la base, c'est à ça que servent les fonctions virtuelles : Supprimer les switch/if, car ils ne sont pas auto-évolutifs.

    Si ce que tu veux est le premier cas, je te conseille de ne pas manipuler directement des pointeurs comme ça, car même si tu fais ce qu'il faut en terme de qui doit détruire, c'est complexe et sujet à erreur, et ce n'est pas explicite à la lecture du code. Tu as ce qu'on appelle les pointeurs intelligents qui te permettent de clarifier l'usage de tes objets.

    En particulier, parmis les cas plus complexes que j'ai pu citer plus tôt, il y en a un d'usage assez courant, où il y a copropriété : Chaque pointeur est co-propriétaire de l'objet, l'objet est détruit dès que son dernier co-propriétaire disparaît. On peut implémenter ce comptage de référence en C++ simplement en utilisant boost::shared_ptr<Vehicule> au lieu de Vehicule*. Une autre solution pour ce mode de partage est d'avoir un garbage collector (comme celui gratuit de Boems), mais je n'en ai pas encore utilisé en C++, et ne peut donc te faire de retour d'expérience.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Membre à l'essai
    Inscrit en
    Octobre 2004
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 15
    Points : 16
    Points
    16
    Par défaut
    Il s'agit bien d'un vecteur de pointeur vector<Vehicule*>. C'est donc bien du cast implicite.

    Je n'ai pas envie que la méthode appelante puisse deleter mes objets placés dans la liste. Et l'argument sur la dure réutilisation du code avec un switch ma convaincu de travailler avec les méthodes virtuelles clone().

    Un grand merci pour cette réponse de qualité en tt cas. Ca m'aide beaucoup!

    sur ce, je flag ce post en "Resolu", et je pars sur la route du codage des Clones

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

Discussions similaires

  1. Constructeur par copie et classe abstraite
    Par Benlev dans le forum C++
    Réponses: 15
    Dernier message: 30/10/2009, 18h01
  2. Héritage et constructeur par copie
    Par Mindiell dans le forum C++
    Réponses: 3
    Dernier message: 31/12/2008, 11h26
  3. [Debutant] Problème avec un constructeur par copie
    Par Drannor dans le forum Débuter
    Réponses: 5
    Dernier message: 12/03/2007, 09h15
  4. Constructeur par copie et std::list
    Par Captain_JS dans le forum SL & STL
    Réponses: 5
    Dernier message: 13/12/2005, 19h15
  5. [deb.]Constructeur par copie
    Par Marc_3 dans le forum Débuter
    Réponses: 4
    Dernier message: 19/11/2005, 13h33

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