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

[C++] Utiliser un std::vector pour stocker des pointeurs vers des objets ?

godrik
godrik
Niveau 30
06 août 2019 à 20:25:56

Mouais, sauf que c'est un modele qui marche differement pour les atouts qui vont jusqu'a 21 ou pour l'excuse qui n'a pas de valeure numerique.

Donc tous les codes vont se retrouve a devoir utiliser une abstraction de plus haut niveau et comparer les cartes deux a deux en fonction de leur types. et de leur valeure si ca a de l'importance. Donc dans un cas tu vas faire:
carte_a.getType() == carte_b.getType() et dans l'autre tu vas faire getType(carte_a) == getType(carte_b). Ca qui revient a dire qu'en terme d'expressivite c'est pareil.

Note que tu ne fera pas char carte = 2; mais plutot Carte c = Carte::Coeur_2; en utilisant Carte comme un scoped enum backe par un type unsigned char. Ca te donne:

  1. un type compacte en memoire qui fait que quand tu va faire des simulations pour l'IA, tu ne vas pas craque la memoire de la machine
  2. un mapping entre carte et des entiers qui commencent a 0 ce qui te permet de te servir de carte comme index dans des tableau ou des bit flags. Et pouvoir faire deja_jouer[(int)c] = true; c'est quand meme pas mal.
  3. pas de confusion de type entre Carte et char parceque dans le systeme de type ils sont different, mais physiquement ils sont pareil.
  4. pas de possibilite d'avoir de valeure impossible dans ton type Carte a moins de le faire expres avec des cast dangereux
lokilok
lokilok
Niveau 17
06 août 2019 à 20:38:19

A la base tu avais pas parlé d'énum, ou alors j'ai mal lu.

Mais sinon ça reste une mauvaise idée les énumérations, à l'utilisation c'est plus ou moins propre mais à l'écriture c'est long (tu dois quand même créer 78 énumérations c'est long).

Donc dans un cas tu vas faire:

carte_a.getType() == carte_b.getType() et dans l'autre tu vas faire getType(carte_a) == getType(carte_b) . Ca qui revient a dire qu'en terme d'expressivite c'est pareil.

Mais ta fonction getType elle ressemble à quoi ? Elle sera compliquée, soit tu fais un switch sur les 78 valeurs ce qui est horrible, soi tu cast en char pour checker si le nombre derrière l'enum appartient entre les deux bons ID, c'est plus simple mais c'est pas très beau. Alors que si tu avais une classe ta fonction getType contiendrait uniquement un "return type" ce qui est infiniment plus simple et moins enclin aux erreurs.

Et c'est pareil pour la ton getNumber, tu devras caster en char et faire un modulo et des soustractions selon le type, source d'erreur potentielle aussi, alors qu'un getNumber dans une classe qui retourne number c'est impossible de se tromper.

Donc tous les codes vont se retrouve a devoir utiliser une abstraction de plus haut niveau et comparer les cartes deux a deux en fonction de leur types.

Pourquoi ça ? Tu as juste à overload l'opérateur == (ce qui se fait très simplement, une ligne) et tu as exactement le même comportement que ton énumération.

Mouais, sauf que c'est un modele qui marche differement pour les atouts qui vont jusqu'a 21 ou pour l'excuse qui n'a pas de valeure numerique.

Le constructeur de ta carte class aura 3 if, c'est tout, c'est pas plus compliqué que de devoir créer 78 énumérations, sans compter tout le reste, et en plus de ça ça augmente la sécurité.

En gros le seul avantage de l'énumération serait un gain de performance, mais à côté de ça t'as que des inconvénients plus ou moins gros, et comme on dit "une optimisation prématurée est la source de tous les maux", et je pense que dans ce cas ça s'applique.

Message édité le 06 août 2019 à 20:40:41 par lokilok
godrik
godrik
Niveau 30
06 août 2019 à 23:57:51

(Ca sera mon dernier message sur le topic parceque je pense qu'on a perdu OP il y a 10 messages)

Le 06 août 2019 à 20:38:19 lokilok a écrit :
A la base tu avais pas parlé d'énum, ou alors j'ai mal lu.

En C++ tu ne passe jamais un type primitif nul part. Tu le redecore toujours pour avoir les operations que tu veux

Mais sinon ça reste une mauvaise idée les énumérations, à l'utilisation c'est plus ou moins propre mais à l'écriture c'est long (tu dois quand même créer 78 énumérations c'est long).

Si tu l'ecris a al main oui. perso, je genere ce genre de chose.

Donc dans un cas tu vas faire:

carte_a.getType() == carte_b.getType() et dans l'autre tu vas faire getType(carte_a) == getType(carte_b) . Ca qui revient a dire qu'en terme d'expressivite c'est pareil.

Mais ta fonction getType elle ressemble à quoi ? Elle sera compliquée, soit tu fais un switch sur les 78 valeurs ce qui est horrible, soi tu cast en char pour checker si le nombre derrière l'enum appartient entre les deux bons ID, c'est plus simple mais c'est pas très beau. Alors que si tu avais une classe ta fonction getType contiendrait uniquement un "return type" ce qui est infiniment plus simple et moins enclin aux erreurs.

Et c'est pareil pour la ton getNumber, tu devras caster en char et faire un modulo et des soustractions selon le type, source d'erreur potentielle aussi, alors qu'un getNumber dans une classe qui retourne number c'est impossible de se tromper.

Ca s'ecrit en 10 minutes tests inclus, si tu n'as jamais ecrit ce genre de chose de ta vie.

Donc tous les codes vont se retrouve a devoir utiliser une abstraction de plus haut niveau et comparer les cartes deux a deux en fonction de leur types.

Pourquoi ça ? Tu as juste à overload l'opérateur == (ce qui se fait très simplement, une ligne) et tu as exactement le même comportement que ton énumération.

La comparaison c'est pas juste l'egalite, et c'est une comparaison que tu ne fais jamais au tarot. La comparaison que tu veux est "est ce que cette carte est plus forte que cette carte?" ca s'est une comparaison qui depend du contexte du pli, donc il va te falloir de l'information contextuelle pour repondre a la question. La question "est ce que j'ai le droit de jouer cette carte?" depend egalement du plis.

Mouais, sauf que c'est un modele qui marche differement pour les atouts qui vont jusqu'a 21 ou pour l'excuse qui n'a pas de valeure numerique.

Le constructeur de ta carte class aura 3 if, c'est tout, c'est pas plus compliqué que de devoir créer 78 énumérations, sans compter tout le reste, et en plus de ça ça augmente la sécurité.

Note que c'est un constructeur que tu n'appellera qu'une fois parceque tu vas toujours construire un tas d'un coup. Donc tu vas devoir ecrire le code qui va generer les 78 cartes en appellant les 78 appels valide du constructeurs. (Et c'est le meme code que tu ecris pour generer l'enum.)

En gros le seul avantage de l'énumération serait un gain de performance, mais à côté de ça t'as que des inconvénients plus ou moins gros, et comme on dit "une optimisation prématurée est la source de tous les maux", et je pense que dans ce cas ça s'applique.

Sauf que pour pouvoir indexer sur les cartes tu va te retrouver a ecrire une fonction de hashage ou/et des comparateurs. Et tu vas avoir besoin de ces trucs la pour construire ton IA, ou simplement pour mapper un sprite a chaque carte. Et tu va ecrire du code gore partout dans l'application, parce que la logique du tarot est blinde de cas particulier.

lokilok
lokilok
Niveau 17
07 août 2019 à 01:17:22

Je dis pas que c'est pas possible, je dis juste que c'est plus compliqué, tout ce que tu me dis m'a l'air plus compliqué à mettre en place que ce dont je parle, pour au final de l'optimisation qui sera très certainement inutile dans le cas de l'auteur, c'est pour ça que je vois pas en quoi ça peut être une bonne idée.

La comparaison c'est pas juste l'egalite, et c'est une comparaison que tu ne fais jamais au tarot. La comparaison que tu veux est "est ce que cette carte est plus forte que cette carte?" ca s'est une comparaison qui depend du contexte du pli, donc il va te falloir de l'information contextuelle pour repondre a la question. La question "est ce que j'ai le droit de jouer cette carte?" depend egalement du plis.

Oui enfin dans ces cas là tu écriras le même code pour les énumérations ou pour la classe, aucune facilité ajouté donc.

Note que c'est un constructeur que tu n'appellera qu'une fois parceque tu vas toujours construire un tas d'un coup. Donc tu vas devoir ecrire le code qui va generer les 78 cartes en appellant les 78 appels valide du constructeurs. (Et c'est le meme code que tu ecris pour generer l'enum.)

Effectivement, même si perso je trouve ça quand même plus propre d'avoir les 78 cartes générées dans le code directement que de générer du code séparément pour ensuite l'inclure.

Sauf que pour pouvoir indexer sur les cartes tu va te retrouver a ecrire une fonction de hashage ou/et des comparateurs. Et tu vas avoir besoin de ces trucs la pour construire ton IA, ou simplement pour mapper un sprite a chaque carte. Et tu va ecrire du code gore partout dans l'application, parce que la logique du tarot est blinde de cas particulier.

Ta fonction de hash c'est une multiplication et une addition, pour le reste que tu ais une énumération ou la classe ça sera pareil, encore une fois comme je disais plus tôt à l'utilisation les énumérations c'est pas plus facile, mais écrire la classe Carte sera plus simple et plus propre que de faire tes helpers getType / getNumber et la génération des énumérations.

Enfin bref, pour résumer les énumérations c'est plus compliqué à implémenter, tu dois écrire un outil pour te générer du code sinon c'est chiant, et ça t'apporte qu'un peu d'optimisation qui est vraiment inutile dans le cas de l'auteur, à côté de ça tu peux utiliser une classe où toutes tes fonctions feront très peu de lignes et seront très rapidement compréhensibles et le tout en utilisant uniquement ce que le langage propose sans devoir passer par des outils tiers pour générer du code, pour moi le choix est vite fait.

Message édité le 07 août 2019 à 01:22:09 par lokilok
Sous forums
  • Aide à l'achat Mac
  • Création de sites web
  • Internet
  • Macintosh
  • Création de Jeux
  • Linux
  • Programmation
  • Steam Deck
  • Hardware
La vidéo du moment