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 :

Problème de polymorphisme dynamique


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Par défaut Problème de polymorphisme dynamique
    Bonjour à tous,

    Je dois implémenter une interface et la tester. Comme mon problème est difficile à expliquer et à comprendre sous forme de prose, je vous le soumets sous forme d'un code prenant l'exemple d'un garage :

    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
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
     
    #etc...
    // Mon interface
    class InterfaceVoiture
    {
    public :
     
    	void InterfaceVoiture();
     
    	virtual void accelerer() = 0;
     
    	virtual void freiner() = 0;
     
    	virtual int getVitesseMax() = 0;
     
    	virtual std::string getMarque() = 0;
    }
     
    // Mon implémentation
    class Voiture : public InterfaceVoiture
    {
    protected :
     
    	int vitesseMax;
     
    	std::string marque;
     
    public :
     
    	Voiture() :
    		vitesseMax{130},
    		marque{"Peugeot"}
     
    	virtual void accelerer();
     
    	virtual void freiner();
     
    	virtual int getVitesseMax();
     
    	virtual std::string getMarque();
    }
     
    // Une autre classe devant agréger mon implémentation
    class Garage
    {
    protected :
     
    	// Ici je suis obligé de fournir l'interface et non l'implémentation :
     
    	// Cela permet à garages de contenir des classes de test triviales (des mocks) de voitures
    	// et cela fait partie du cahier des charges...
    	std::vector<InterfaceVoiture*> voitures;
     
    	...
     
    public :
     
    	// Même remarque que ci-dessus 
    	InterfaceVoiture* getVoitureAt(int index){return voitures.at(index);}
     
    	...
     
    }
     
    // Ma classe de test de l'implémentation
    class TestVoiture 
    {
    protected :
     
    	Garage* garage;
     
    	// Je dois tester la classe voiture en créant d'abord un garage
    	Voiture* voitureATester;
     
    public :
     
    	void testerVoiture(int index)
    	{
                    garage = new Garage();
                    voitureATester = new VoitureATester();
     
    		// Malheureusement à cause des contraintes le getter du garage est une InterfaceVoiture* et non une Voiture*...
    		voitureATester = dynamic_cast<Voiture*>(garage->getVoitureAt(index));
     
    		// Évidemment, une interface ne possède pas d'attribut, donc les getters ci-dessous renvoient une SEH exception,
    		// i.e. un pointeur non initialisé...
    		std:: cout << voitureATester->getVitesseMaxVoiture() << std::endl; // 130
     
    		std::cout << voitureATester->getMarqueVoiture() << std::endl; // Peugeot
    	}
    }
    Comment obtenir la vitesse maximale de la voiture et sa marque sachant :

    - Que l'on doit obtenir ces valeurs en créant une voiture contenue dans un garage créé dans la classe de test
    - Que le getter permettant d'obtenir une voiture dans la classe "Garage" doit être une interface ?

    Inutile de remarquer certaines horreurs telles que l'initialisation des attributs de la voiture à 130 ou "Peugeot" directement, je l'ai fait pour simplifier.

    Merci d'avance pour vos réponses !

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Qu'est censé retourner getVoitureAt() quand la collection est vide?
    Et pourquoi de pas directement déclarer voitureATester avec le type InterfaceVoiture?

    PS: La voiture allouée à la ligne 81 est leakée par le code actuel.
    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.

  3. #3
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Par défaut
    Bonjour, merci pour votre prompte réponse !

    Citation Envoyé par Médinoc Voir le message
    Qu'est censé retourner getVoitureAt() quand la collection est vide?
    Dans mon "vrai" code, je renvoie une exception... Mais c'était pour simplifier le problème car si j'écris tout, cela devient trop long...

    Citation Envoyé par Médinoc Voir le message
    Et pourquoi de pas directement déclarer voitureATester avec le type InterfaceVoiture?
    En fait, je dois tester une instance de la classe Voiture... J'ai tout de même essayé de déclarer voitureAtester en tant qu'InterfaceVoiture :

    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
     
    class TestVoiture
    {
    protected :
    	InterfaceVoiture* voitureATester;
    	Garage* garage;
    	...
     
    public :
    	void testerVoiture(int index)
    	{
                    garage = new Garage();
    		voitureATester = new Voiture(); // La voiture à tester doit être une Voiture et non une InterfaceVoiture car je dois tester 
    		// la classe Voiture et ses getters ci-dessous...
     
    		voitureATester = dynamic_cast<Voiture*> garage->getVoitureAt(index);
     
    		std:: cout << voitureATester->getVitesseMaxVoiture() << std::endl; // 130
     
    		std::cout << voitureATester->getMarqueVoiture() << std::endl; // Peugeot
    	}
    }

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    S'il te plait, poste au moins le code complet de la classe TestVoiture, parce que pour l'instant les extraits que tu as postés défient la logique (fuites mémoire, objets re-créés sans raison apparente, etc. ).
    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.

  5. #5
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    S'il te plait, poste au moins le code complet de la classe TestVoiture, parce que pour l'instant les extraits que tu as postés défient la logique (fuites mémoire, objets re-créés sans raison apparente, etc. ).
    Pardon... J'ai remis la déclaration de voitureATester en tant que Voiture* car j'ai besoin de ses attributs pour attributs pour appeler les getters getVitesseMaxVoiture() et getMarqueVoiture()...

    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
    class TestVoiture 
    {
    protected :
     
    	Garage* garage; 
    	// Je dois tester la classe voiture en créant d'abord un garage
    	Voiture* voitureATester;
     
    public :
     
    	void testerVoiture(int index)
    	{
    		garage = new Garage();               
     
    		// Malheureusement à cause des contraintes le getter du garage est une InterfaceVoiture* et non une Voiture*...
    		voitureATester = dynamic_cast<Voiture*>(garage->getVoitureAt(index)); 
     
    		// Évidemment, InterfaceVoiture ne possède pas d'attribut, donc les getters ci-dessous renvoient une SEH exception,
    		// i.e. un pointeur non initialisé...
    		std:: cout << voitureATester->getVitesseMaxVoiture() << std::endl; // 130
     
    		std::cout << voitureATester->getMarqueVoiture() << std::endl; // Peugeot
     
    		delete garage; // La voiture sera détruite à l'appel du destructeur du garage		
    	}
    }
    Rappel du code testé :

    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
    #etc...
    // Mon interface
    class InterfaceVoiture
    {
    public :
     
    	void InterfaceVoiture();
     
    	virtual void accelerer() = 0;
     
    	virtual void freiner() = 0;
     
    	virtual int getVitesseMax() = 0;
     
    	virtual std::string getMarque() = 0;
    }
     
    // Mon implémentation
    class Voiture : public InterfaceVoiture
    {
    protected :
     
    	int vitesseMax;
     
    	std::string marque;
     
    public :
     
    	Voiture() :
    		vitesseMax{130},
    		marque{"Peugeot"}
     
    	virtual void accelerer();
     
    	virtual void freiner();
     
    	virtual int getVitesseMax();
     
    	virtual std::string getMarque();
    }
     
    // Une autre classe devant agréger mon implémentation
    class Garage
    {
    protected :
     
    	// Ici je suis obligé de fournir l'interface et non l'implémentation :
     
    	// Cela permet à garages de contenir des classes de test triviales (des mocks) de voitures
    	// et cela fait partie du cahier des charges...
    	std::vector<InterfaceVoiture*> voitures;
     
    	...
     
    public :
     
    	// Même remarque que ci-dessus 
    	InterfaceVoiture* getVoitureAt(int index){return voitures.at(index);}
     
    	...
     
    }

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Ton code devrait péter dès ce point:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    		garage = new Garage();               
     
    		// Malheureusement à cause des contraintes le getter du garage est une InterfaceVoiture* et non une Voiture*...
    		voitureATester = dynamic_cast<Voiture*>(garage->getVoitureAt(index));
    Parce que tu fais un getVoitureAt() sur un garage vide, et donc le Garage::voitures lance une std::out_of_bounds...
    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.

  7. #7
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Par défaut Ne jamais oublier les constructeurs de copie !
    Médinoc,

    Après avoir modifié mon code pour que le garage se remplisse d'une voiture à sa construction, je suis toujours tombé sur la SEH exception et j'ai continué à débugger.

    Je m'aperçois alors que voitureATester ne possède pas les mêmes attributs que garage->getVoitureAt(index)... En fait, j'ai oublié de définir un constructeur de copie pour la classe Voiture !!

    Je le définis alors, et j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    voitureATester = new Voiture(dynamic_cast<Voiture*>(garage->getVoitureAt(index)));
    Et voilà... Malgré le fait que voitureATester soit une Voiture*, on peut parfaitement retourner une InterfaceVoiture* pour getVoitureAt() dans le cadre des contraintes citées plus haut et le caster en Voiture* sans perdre des données ou attributs, contrairement à ce que je pensais.

    La perte d'attributs provenait du fait que le constructeur de copie par défaut n'était pas suffisant, d'où la nécessité de ne jamais oublier le constructeur par copie. Merci Médinoc pour ton aide !

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

Discussions similaires

  1. [HTML+CSS] Problème de menu "dynamique"
    Par Invité dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 06/04/2005, 12h48
  2. Question sur les problèmes d'allocation dynamique
    Par slylafone dans le forum C++
    Réponses: 23
    Dernier message: 25/10/2004, 14h18
  3. [JSP]Problème liste deroulante dynamique
    Par besco dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 09/09/2004, 17h58
  4. problèmes de textes dynamique dynamiquement générés
    Par stephane eyskens dans le forum Flash
    Réponses: 18
    Dernier message: 05/09/2003, 13h13
  5. [Rave Report] problème de création dynamique
    Par Nivux dans le forum Rave
    Réponses: 2
    Dernier message: 24/05/2003, 00h07

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