Bonjour,
Merci
Bonjour,
Merci
Normalement, dans le mécanisme d'héritage, la première chose à faire est d'appeler le construteur de la classe mère à l'aide de le liste d'initialisation....
Ben je sais pas trop comment t'as implementé les classes "Personnes" et "vacanciers", mais visiblement, ta fonction "achat_glace" ne fais pas partie de la classe "Personne".
Tu as deux possibilités :
1/ declarer tmp en tant que vecteur de vacanciers : vector<vacancier *> tmp;
2/ declarer un fonction virtuelle "achat_glace" dans la classe "personne" et la redefinir dans la classe "vacanciers", comme ça :
- elle fait partie de la classe "personne"
- etant virtuelle, si tu crée une instance de "vacanciers" et que tu appelles la fonction "achat_glace" sur cette instance via un pointeur de type "personne", c'est la bonne implémentation qui est appelée (celle de type "vacanciers")
La seconde solution est bien meilleure et permet de réelement tirer parti de l'héritage.
Si tu n'es pas familier avec ça, je te conseille les tutoriaux sur l'heritage et le polymorphisme.
C'est un objet Vacancier que tu crees mais tu le definis comme Personne. Vacancier derive de Personne donc un Vacancier est bien une Personne, le "cast" est autorisé. Cependant, une fois que c'est defini en Personne tu ne peux pas utiliser les methodes propres a la classe fille (Vacancier) a moins de recaster dans l'autre sens.
Remplace donc simplement cette ligne par :
Code : Sélectionner tout - Visualiser dans une fenêtre à part Vacancier * vacancier = new Vacancier();
Oui.Admettons que 10 classes héritent de Personne.
Toutes ces classes auront une méthode "achat_glace" alors que seul la classe Vacancier en a besoin.
C'est bien ce qui se passera ?
Non, c'est un objet Vacancier, mais le pointeur *vacancier pointe sur un objet de type personne. Qui ne connait donc que les méthodes de la classe "personne"Personne * vacancier = new Vacancier();
C'est un objet Personne qui est crée ?
Ben l'interet, c'est justement de pouvoir utiliser un pointeur "generique" (ici un pointeur sur un objet "personne" et qu'en fonction du type d'objet instancié (ici Vacancier) les méthodes appelées ont le même nom mais pas la meme implémentation.Je ne vois pas très bien l'intéret de mettre "achat_glace" dans la classe Personne car cette méthode ne concerne que des Vacancier.
Revoit peut-etre un peu l'architecture de tes classes. Dans la classe Personne, seul les fonctions communes doivent y figurer. Tu pourrais par exemple faire une fonction "achat(objet)" qui en fonction du type de personne et du type d'objet n'aura pas la meme fonctionnalité.
Pour ça, tu fais une classe Objet qui a tous les parametres communs (prix, poids, taille...) et une procedure du type "getObjectType"
Dans ta fonction achat (specifique à un vacancier), tu fais :
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 Vacancier::achat(Objet *objet) { if (objet->getObjectType() == "glace") { ......... } if (objet->getObjectType() == "frite") { ......... } if (objet->getObjectType() == "saucisse") { ......... } if (objet->getObjectType() == "menuComplet") { ...... } }
J'oubliais....
L'interet de tout ca, c'est que dans ton code, apres tu peux faire :
Objet *pObjet = new Biere();
ou
Objet *pObjet = new Glace();
ou
Objet *pObjet = new Saucisse();
ou
Objet *pObjet = new PaireDeTonguesEnPlastiques();
et
Personne *pPersonne = new Vacancier();
ou
Personne *pPersonne = new Vendeur();
ou
Personne *pPersonne = new Nudiste();
ou
Personne *pPersonne = new Policier();
et appeler simplement :
pPersonne->achete(pObjet);
Tu auras automatiquement :
"Un Vacancier a acheté une glace"
ou
"un vendeur ne peut acheter de saucisses"
ou
"A poil les nudistes, on met pas de tongues"
ou
"Pas de biere pour les policiers pendant le service"
ou
.....
Oui oui, c'est le polymorphisme décrit plus haut.
Lit le tuto sur le polymorphisme, c'est tres instructif !
Il existe une 3eme solution.
Comme parano le dit, la methode achat_glace ne concerne que les vacanciers. En consequence elle n'a rien a faire dans la classe parente. Le polymorphisme est utile seulement si plusieurs classes filles ont besoin de methodes similaires ce qui ne semble pas etre le cas ici.
Donc la solution consiste a garder achat_glace dans Vacancier et a la sortie du vecteur de faire un dynamic_cast pour pouvoir appeler la methode de la classe fille. Si ce qui sort du vecteur n'est pas un vacancier, mais un autre type de personne, le dynamic_cast evitera les problemes.
Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]);
vacancier->achat_glace();
Ouais, mais le dynamic_cast, pour moi c'est un peu du bricolage...
Et achat_glace n'a rien a faire dans personne, mais je presume qu'il n'y a pas que les vacanciers qui peuvent acheter, et pas que des glaces, donc autant mettre ca dans l'architecture des le depart...
Dans ton code :
Il ne faudrait pas mieux faire
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]); vacancier->achat_glace();
Parce que il me semble que dynamic_cast renvoit NULL si l'objet n'a pas pu etre casté. Et dans ce cas, l'appel à vacancier->achat_glace(); declenchera une exeption !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]); if (vacancier != NULL) vacancier->achat_glace();
Oui pardon , c'est justement ca qui protege (pouvoir verifier si le cast s'est bien passé)
Dynamic_cast n'est pas du bricolage. Il est typiquement fait pour gerer pleins d'instances de classe fille comme des instances de la classe mere jusqu'au moment ou la distinction est necessaire.
Quand je vois qu'il a un Glacier comme personne, il est peu probable que le Glacier achete quoiquecesoit (lui il vend). Donc une methode acheter n'a pas d'interet pour lui.
Ou alors il faut rajouter un niveau de classe : Creer les classes Vendeur et Acheteur derivant de la classe Personne. Puis Deriver vendeur pour creer Glacier/Boulanger et de l'autre coté deriver Acheteur en Vacanciers/Nudiste/Villageois. Dans ce cas mettre achat dans la classe Acheteur et utiliser le polymorphisme a un sens. De meme qu'on pourrait mettre vendre dans Vendeur.
Ben le glacier, faut bien qu'il achete des fournitures, non ?
Et s'il a envie de se ballader en tongues en buvant une biere, faut bien qu'il puisse les acheter ?
Par contre une méthode "prepareUneGlace()" n'aurait pas de sens pour un policier, et une méthode "seFoutAPoil()" n'aurait pas de sens pour le glacier...
En allant plus loin, nudiste pourrait etre une interface, car le policier peut se foutre à poil s'il fait partie des chippendales du samedi soir....
Dans tout les cas, mieux vaut passer 3 jours avec un crayon et un papier pour reflechir et dessiner son shema de classes plutot que d'etre obligé de bricoler par la suite.
@parano : je te conseilles vivement de lire les tutos, de reflechir à tes besoins réels, de tracer un schéma (meme approximatif).
Ensuite le code viendra de lui-meme tellement il sera logique.
En fait, c'est paske pour utiliser le dynamic_cast, il faut que ta classe possede une v_table.
Une v_table, c'est une table interne au compilateur qui contient les infos de types et les adresses des fonctions virtuelles.
Donc pour generer une v_table, il te suffit de declarer une des fonctions en virtuelle.
Par exemple le constructeur ou le destructeur.
Du coup, le compilo genere une v_table, et le dynamic_cast fonctionne !
Une v_table, c'est une table interne au compilateur qui contient les infos de types et les adresses des fonctions virtuelles.[/quote[Envoyé par buzzkaido
La vtable ne se trouve pas dans le compilateur, mais dans l'executable
Tu m'expliques comment declarer un constructeur virtuel?Donc pour generer une v_table, il te suffit de declarer une des fonctions en virtuelle.
Par exemple le constructeur ou le destructeur.
Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.
Ben, tu met virtual devant la declaration du constructeur.
Et t'obtiens une belle erreur de compilation.
Et là tu passes pour un con, et tu retourne lire "Le C++ pour les nuls"
Pour la v_table, "interne au compilateur" je voulais dire "que tu t'en occupes pas, ça se fait tout seul si tu le declenche"
En tout cas, j'aime bien ce forum, ça me permet d'apprendre des trucs et aussi de preciser mes informations sur des domaines dans lesquels je croit savoir...
"if(achat)" suffit !
Code : Sélectionner tout - Visualiser dans une fenêtre à part if(achat == true)
Quelle horreur !}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Vacancier::achat(Objet *objet) { if (objet->getObjectType() == "glace") {//.........
note : si on ne peut déclarer un constructeur virtuel, les "constructeurs virtuels" existent bel et bien en C++ (c'est le pattern Factory Method) !Tu m'expliques comment declarer un constructeur virtuel?
Enfin j'ai une question : pour avoir une liste de Personne* alors que manifestement tu n'y mets que des Vacancier* ? Tu me diras, tu as bien les glaciers, que tu peux d'ailleurs mettre dans une autre liste, disons serviceDePlage.
En premier lieu, utilisez un moteur de recherche.
En second lieu, postez sur le forum adéquat !
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager