CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

Question c++ vecteur de classes dérivés

blen2r
blen2r
Niveau 3
20 juin 2007 à 04:23:22

Bonjour. Voici mon problème: j´ai une classe de base cBase et 2 classes qui en sont dérivées (cRenderable et cNonRenderable). Je cherche une façon d´avoir une liste qui peut en contenir les 3 types.

Pour commencer, j´ai vector<cBase*> myList; je croyais que de cette façon je pourrais y stocker des objets qui sont de classes dérivés mais ce n´est pas le cas. Par exemple si je fais myList.push_back(new cRenderable); il n´y a pas de problème mais si je fais myList.at(0)->bRender = false; (bRender est un bool dans cRenderable) le compilateur me dit que bRender n´est pas membre de cBase, ce qui est normal et je comprends que ça ne peut pas fonctionner. Je me demandais si quelqu´un connaissait une façon de faire ce que je veux, soit une façon d´avoir une liste d´objets qui sont soit cBase, cRenderable ou cNonRenderable.

(J´ai généralisé le problème pour une meilleure compréhension alors je n´ai pas de code source pour aller avec)

Merci!

KeepSmile
KeepSmile
Niveau 4
20 juin 2007 à 09:43:23

Pourquoi ne pas mettre ton boolean bRender dans la class cBase ? comme ceci, toutes tes class dérivant de cBase hériteront de cet attribut et tu pourras y accéder depuis ta list :) .

LGV
LGV
Niveau 28
20 juin 2007 à 10:05:10

en faisant ca, tu perds tout l´interet de l´abstraction.

il faudrait en savoir plus sur le contexte, c´est un pb tres generique qui, pour etre solutionne, proprement peut faire appel a plein de variantes (aggregation, delegation, pure virtual, DP strategy ou visitor, data reflexion, etc.).
Sans plus d´infos, dur de dirigier vers une piste plutot qu´une autre.

Fvirtman
Fvirtman
Niveau 10
20 juin 2007 à 10:21:29

En fait, si je resume, tu veux pouvoir stocker des choux et des carottes dans ta liste de légumes.
Et un moment, tu demandes d´éplucher un élément : or tous les légumes ne s´épluchent pas.
--> Normal que ça gueule.

If faudrait downcaster si vraiment tu veux éplucher.
Par exemple, dire :
je prendre un légume.
Si le legume est une carotte, alors je cast en carotte
et la, je peux éplucher.

Concretement, je te conseille un enum global, au dessus de ta classe globale :

enum legume_type
{
TYPE_LEGUME_GENERIC,
TYPE_LEGUME_CHOUX,
TYPE_LEGUME_CAROTTE
};

class Legume // mere
{

public:
... // tout ce que tu as déja

virtual legume_type GetType(){return TYPE_LEGUME_GENERIC;} // virtual, c´est impotant ici, cas la méthode de la classe filel sera prioritaire.
}

class Choux:public Legume
{

public:
... // tout ce que tu as déja

legume_type GetType(){return TYPE_LEGUME_CHOUX;}
}

class Carotte:public Legume
{

public:
... // tout ce que tu as déja

void Epluche();
legume_type GetType(){return TYPE_LEGUME_CAROTTE;}
}

Du coup, apres, quand tu testes :

Legume* l = myList.at(0);
if (l->GetType()==TYPE_LEGUME_CAROTTE)
{
Carotte* c = (Carotte*)l; // downcast (tu peux te servir de static_cast aussi)
c->Epluche();
}

dnob700
dnob700
Niveau 10
20 juin 2007 à 14:18:17

pareil, je dirais que l´enum fait perdre la généricité.

Par contre, il y a deux possibilité. Si quand tu sors un élément de ta liste tu sais toujours s´il s´agit d´un renderable ou non, alors tu peut le caster dans la bonne classe avant de l´utiliser (dynamic_cast je dirais, mais je ne suis pas sûr du tout). Si tu ne sais pas a priori de quel classe il s´agit, alors c´est moins facile, mais il y a un moyen d´obtenir le type (typeof() ?) d´un objet si les RTTI sont activés dans ton programme. Je ne sais pas du tout comment on s´en sers, mais ça ne doit pas être très dur de trouvé, avec les mots clefs données plus haut.

Fvirtman
Fvirtman
Niveau 10
20 juin 2007 à 14:26:21

dynamic_cast nécessite d´activer les RTTI.
Personnellement, je suis contre les RTTI, j´estime qu´on n´a pas a se trimballer du typage pendant l´execution.

D´une maniere ou d´une autre, si tu veux appliquer une méthode spécifique, il faudra que tu en retires le type, soit via les RTTI (berk!) soit par ma méthode de GetType()
--> tu n´es plus vraiment dans un contexte générique, car tu veux faire quelque chose de spécifique en cas d´un typage ou un autre.

Il est a noter que la méthode de la classe mere que je te propose est virtuelle, mais pas pure, ce qui signifie que tu n´es pas obligé de l´implémenter dans toutes les classes filles. Tu l´implémentes juste si tu en as besoin.

Voila, je défends ma méthode :-)

LGV
LGV
Niveau 28
20 juin 2007 à 14:54:15

ca approche marche pour un module isole, ou un bout de code gere par UN programmeur. Dans un environnement plus complexe, on aura la pbs suivants :

- expose implicitement l´archi de classes
- dependances fortes d´unites logiques
- side-effects & propagation, i.e. difficultes d´extensions: obligation de modifier d´autres parties de code lorsqu´on rajoute ou modifie des choses
- delegue toute la logique au client ; ce qui sous-entend une bonne comprehension des mechanismes internes du module
- rend courante une operation "unsafe" (le downcast maison)

ca marche, et c´est parfaitement adapte a certaines situations ; mais le contexte de programmation veut parfois mettre l´accent sur d´autres contraintes que la fonctionnalites.

Autres idees alternatives :
- base class extensive + override de pure virtual
- derivation et aggregation de components
- multi-heritage et interfaces atomiques
- etc.

LGV
LGV
Niveau 28
20 juin 2007 à 14:55:55

(sinon, pour une methode robuste d´emulation de table de virtualite, Alexandrescu fait ca bien dans son exemple de typage static si je me souviens)

blen2r
blen2r
Niveau 3
20 juin 2007 à 18:50:23

Bonjour merci à tous pour vos réponses!
Alors voici plus spécifiquement ce que je veux faire. Je suis en train d´écrire un engin 2d dans lequel j´utilise une liste d´objets à afficher. Mon engine utilise les "states" pour connaitre les diverses propriétés des objets tels qu´expliqués dans ce blog:
http://72.14.205.104/search?q=cache:KLmF8QWpBfEJ:gbgames.com/blog/%3Fp%3D342+game+development+state+indie&amp;hl=fr&amp;ct=clnk&amp;cd=5&amp;gl=ca&amp;client=firefox-a

Je ne suis pas encore rendu assez loin dans le développement de l´engin pour pouvoir tester les states alors j´ai décidé d´en rajouter une dans la classe cRenderable juste pour voir si je peux y accéder et c´est là que ma question précédente m´est venue en tête. Si j´ai bien compris le blog mentionné plus haut, je devrais faire une classe pour chaque sorte de state (cHITPOINTS, cRENDERSTATE ...). Toutes les classes de mon engin sont dérivées de cBase. cBase contient la méthode "cState* hasState(int un_id_de_state);"

cRENDERSTATE contient le bool qui dit si oui ou non l´objet doit etre affiché. Ma fonction qui s´occuppe d´afficher les objets parcours sa liste d´affichage et pour chaque objet fait if(unObjet->hasState(SRENDERABLE)->bRender)
{...afficher...}
(SRENDERABLE étant l´id d´un state de type cRENDERSTATE)
Le problème est que tel que mentionné dans le premier post je pensais qu´on pouvait stocker des cState et avoir ses dérivés aussi dans le même vecteur.
J´aime bien l´idée de Fvirtman mais dans ce cas je n´utiliserais plus la technique du blog qui me semblait géniale puisque je pouvais accéder aux propriétés de n´importe quel objet en utilisant ses states.

Si vous pensez a un meilleur systeme vous etes les bienvenus car c´est la première fois que j´utilise les states...

Merci bonne journée!

LGV
LGV
Niveau 28
20 juin 2007 à 19:13:37

le blog presente (de maniere assez peu elegante et robuste, au passage..) ce que j´appelle aggregation de components au sens delegation d´interfaces.

l´idee est d´abstraire un service, qui peut ou non etre diponible sur une classe ou ses derivees (ex typique: un GameEntity peut avoir, une ou plusieurs mesh, un physics skeleton, un animation manager, etc.).
Si tu consideres que "renderable" est un "service" sur ce schema, je ne comprends pas ce qui bloque l´implementation ?

blen2r
blen2r
Niveau 3
20 juin 2007 à 19:19:32

désolé mais j´ai du mal à comprendre ce que tu veux dire. (j´étudie en informatique mais je n´ai pas encore fait mes cours d´orienté objet :ouch: j´ai appris sur le tas)

blen2r
blen2r
Niveau 3
20 juin 2007 à 19:26:48

ha ok je crois que j´ai pigé. mais finalement je pense que je vais m´en tenir au système de Fvirtman et trouver une autre facon de faire.

Merci à tous!

Sous forums
  • Aide à l'achat Mac
  • Création de sites web
  • Internet
  • Macintosh
  • Création de Jeux
  • Linux
  • Programmation
  • Steam Deck
  • Hardware