Partage
  • Partager sur Facebook
  • Partager sur Twitter

La POO et le C

Le clash !

    2 mai 2011 à 15:13:41

    Bonjour

    @Taurre et heizmann:
    Vu que le sujet a l'air de beaucoup vous intéresser et qu'il ne me semble pas que le lien ai été donné dans ce fil.

    Object Oriented Programming in C

    Vous devriez trouver quelques pistes(si vous ne connaissiez pas, bien entendu).
    • Partager sur Facebook
    • Partager sur Twitter
    Zeste de Savoir, le site qui en a dans le citron !
      2 mai 2011 à 15:18:37

      -_- lu et relu, en long, large, diagonal et travers :p !!!

      À propos, regardez mes posts et mes codes les pages précédentes, le long de ce fil

      @GurneyH
      • Partager sur Facebook
      • Partager sur Twitter
        2 mai 2011 à 15:25:28

        Citation : heizmann


        Mais je continue à glaner la toile. Il semblerait qu'à ce sujet, un expert en la matière serait Laurent Deniau, et ses fameux projets COS/POOC etc.


        Navré, j'étais passé à travers. :-°
        • Partager sur Facebook
        • Partager sur Twitter
        Zeste de Savoir, le site qui en a dans le citron !
        Anonyme
          2 mai 2011 à 15:43:30

          Je n'ai pas dit qu'il ne fallait pas le faire, j'ai même dit que parfois cela peut etre la moins mauvaise solution. Non juste je trouve pas ça propre. Mais ce n'est que mon avis comme je l'ai fait remarqué, j'ai l'air d'être le seul a le penser.

          Je n'ai pas de solution miracle puisque le C ne propose rien de bien pour le faire (déjà que la forme utilisé en C++ n'est pas terrible ...).

          Et enfin le "comment on pourrait le faire" dépend de la situation d'utilisation et de ce que l'on fait !

          PS: C'est nouveau que l'on vouvoie sur ce site ? Je ne suis pas si vieux que ça pourtant ...
          • Partager sur Facebook
          • Partager sur Twitter
            2 mai 2011 à 16:04:27

            :p moi je vouvoie parce qu'on ne sait jamais à qui on a affaire ! Et puis je suis un peu nouveau ici aussi :-° ... ça me passera sans doute.

            Quoiqu'il en soit :) c'est un débat intéressant, je compte bien m'investir dans un tuto par la suite sur la POO, un truc du genre : "Pensez Orienté Objet" :p ou un truc du genre, et de voir les mécanismes fondamentaux de la POO à travers la POO... quand y'aura matière, je pense ouvrir un fil moi-même afin qu'on partage et collabore des infos pertinentes et idées d'implémentation de POO en C.

            Le but serait surtout pédagogoooo... oups je me répète encore :D ! Et aiderait probablement les gens ayant des connaissances en C pour comprendre ce qu'est la POO :) , ce à quoi elle pourrait bien servir et naturellement justifier le fait qu'il ne s'agit pas d'un langage, mais bien d'une façon de penser - d'où l'implémentation possible en C ( ^^ euh... et en ADA ? hahaah !! Je blague)

            Autre chose - pas nécessairement en rapport direct avec la quelconque création d'un tuto :-° ... Un truc qu'il faudrait éclaircir au risque de me répéter, serait qu'on puisse se mettre d'accord sur une façon "standard" de penser POO en C. Notamment en ce qui concerne le rôle que pourrait avoir le préprocesseur, et puis aussi préciser sur les mécanismes d'autogestion des VTables - si possible. :) on pourrait sans doute faire des trucs très intéressants, et dynamique.

            Je pense que cette semaine je vais tâcher de rédiger une ébauche de cahier des charges d'implémentation de POO en C, histoire qu'on fonctionne tous dans un référentiel commun, qu'en pensez-vous ?
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              2 mai 2011 à 16:13:39

              Même si c'est très intéressant, je ne pense pas qu'un tuto sur la question soit si intéressant. Car même si c'est "fun" et cela peut avoir (très rarement) de l'utilité, globalement autant prendre un langage OO directement, au moins tu leur aprend la POO avec un langage adapté. Car là juste sur les bidouilles de syntaxe tu en perdra les 3/4
              • Partager sur Facebook
              • Partager sur Twitter
                2 mai 2011 à 16:30:09

                Peut-être, peut-être... cela dit, encore une fois ma prétention n'est pas de réinventer la roue (GObject par exemple), plus de comprendre comment on peut implémenter des idées OO avec un langage de programmation.

                J'ai pas envie de développer pour le moment un truc sérieux sur le sujet - d'autres l'ont fait déjà avant moi. Mais cela pourrait être un bon moyen pour comprendre - et partager - les mécanismes subtils dont on peut être amené à se servir en C :) (VTables, X-macros...) pour résumer : cela serait une occasion de réinvestir les différents points abordés dans les cours du site du Zér0 ;) autour d'un "projet" commun : l'implémentation de l'OO en C.
                • Partager sur Facebook
                • Partager sur Twitter
                  2 mai 2011 à 16:42:34

                  Citation : ChristopheG


                  J'ai dut mal a croire que cela soit souvent nécessaire de le faire. Tu a souvent besoin de faire 36 fonctions avec chaque types possibles et inimaginable ?
                  C'est très pratique, j'en convient, mais mise a part pour des bibliothèque générique, cela n'ai pas franchement courant de devoir utiliser beaucoup de types sur une même fonction. Et si tu veux pouvoir changer facilement avant compilation, tu peux utiliser un typedef. En général si tu réfléchis bien ton code, tu peux t'en passer (a part pour des cas comme des listes)



                  C'est certains qu'il est rarement nécessaire de disposer de foncions identiques prenant des arguments de types différents, d'autant que le plus souvent on peut régler ce genre de situation via des pointeurs génériques ou autres. Maintenant, mon exemple traitait d'une utilisation du processeur se rapprochant de l'idée de template en C++ (j'ai bien dit se rapprocher hein :p ) et dont l'idée de base est bien de reproduire un morceau de code à l'identique, mais utilisant des types différents (évidemment le mécanisme proposé par le C++ va bien plus loin et est plus souple qu'une utilisation du préprocesseur, mais l'idée est là).

                  Citation : ChristopheG


                  Que ça existe ne veut pas dire que c'est propre pour autant. On peut tout trouver, le problème n'est pas là. Il est probable que dans ce cas c'étais la solution la moins mauvaise, mais je ne trouve toujours pas ça terrible.



                  Mon exemple visait à répondre au fait qu'une solution utilisant le préprocesseur n'était pas viable pour un code "plus complexe", à mon sens il démontre que cela peut l'être. Maintenant, sur le fait que cela soit propre ou non chacun est juge, j'aurais personnelemnt tendance à trouver cela propre du moment que les noms et fonctions des macros sont claires et que les précautions d'usages sont prisent (ce qui est le cas ici).

                  Citation : ChristopheG


                  Même si c'est très intéressant, je ne pense pas qu'un tuto sur la question soit si intéressant. Car même si c'est "fun" et cela peut avoir (très rarement) de l'utilité, globalement autant prendre un langage OO directement, au moins tu leur aprend la POO avec un langage adapté. Car là juste sur les bidouilles de syntaxe tu en perdra les 3/4



                  Un LOO est-il vraiment adapté pour apprendre la POO? :-°
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    2 mai 2011 à 16:47:45

                    Ce n'étais pas une attaque personnel hein. Je comprend tout a fait la démarche. J'ai juste un peu de mal avec l'utilisation massive du pré-processeur.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      2 mai 2011 à 16:52:41

                      Citation : ChristopheG


                      Ce n'étais pas une attaque personnel hein



                      Qu'est ce qui te fait dire cela? o_O

                      Citation : ChristopheG


                      J'ai juste un peu de mal avec l'utilisation massive du pré-processeur.



                      Aucun problème pour moi, je comprends tout à fait ;)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        2 mai 2011 à 17:15:43

                        @Taurre & ChristopheG :p !!! Arf, on se chamaille ?

                        Excusez-moi c'est vrai là je n'ai pas trop le temps pour lire et surtout analyser les remarques faites en cours de route. Ceci étant :

                        Qui est "chaud" pour se lancer dans le cahier des charges d'une approche OO en C ???
                        • Partager sur Facebook
                        • Partager sur Twitter
                          3 mai 2011 à 0:57:54

                          Citation : QuentinC 2

                          a- C'est aussi là qu'on se rend compte de certains manques à mon avis complètement idiots du C++, comme par exemple l'interdiction d'appeler les constructeurs d'une même classe en cascade (notons que je suis plutôt un amateur de java, donc certains points particuliers du C++ me paraissent être de véritables hérésies)

                          b- Exceptions: avec setjmp et longjmp... par contre ça devient vite le bordel avec l'allocation dynamique... C'est là qu'on se rend comtpe à quel point les desctucteurs ont été une magnifique invention, et à quel point les systèmes de GC sont encore bien mieux que ça puisqu'ils passent complètement par-dessus le problème.

                          c- Surcharge d'opérateur: c'est juste un bonus syntaxique

                          d- Surcharge de méthode: pareil, c'est aussi un bonus syntaxique... comme déjà montré dans un post précédent, essayer d'en faire c'est vraiment du gros bidouillage.

                          e- Programmation générique avec type erasure: le void* suffit largement, sauf si on doit gérer les types primitifs (ce qui permet de comprendre pourquoi les génériques de java ne peuvent pas utiliser les types primitifs; en cela, les templates du C++ constituent plus une armée de moines copistes intelligents que de la véritable programmation générique, puisque chaque classe et chaque fonction est recopiée pour chaque type utilisée (ne me tuez pas, je ne suis pas un expert C++ et je n'ai pas lu stroustrup))

                          f- Là où ça commence à devenir vraiment intéressant, c'est pour les interfaces. Là je commence à avoir du mal de comprendre comment ça fonctionne exactement. Définir une interface c'est pas compliqué (juste une vtable de plus avec uniquement des méthodes abstraites), c'est ensuite que je coince. Si par exemple j'ai deux interfaces I1 et I2, une classe A qui implémente ces deux interfaces, comment un pointeur sur I1 pointant en réalité sur une instance de A peut-il être converti en pointeur sur I2 ? Ou en d'autre termes, comment fonctionne dynamic_cast en C++, ou ce genre de cast en java ?


                          a- Le forward de constructeurs (depuis un même type), et l'héritage de constructeurs ont été rajoutés au C++11.

                          b- Les systèmes à GC se limitent à la mémoire. Ils ne comprennent rien aux autres ressources : fichiers, sockets, pot de peintures, etc.
                          De plus les GC tendent à être non déterministes. Souvent un mieux (pour les optimisations permises), parfois une catastrophe.

                          Les destructeurs (on dit RAII, ou RRID en C++), c'est déterministe et implicite.

                          c- Certes, mais appréciable, et sans rapport avec le débat (OO). Les SAXPY des BLAS, j'en ai assez gouté, merci.

                          d- C'est vrai. Mais de nouveau, cela n'a rien de OO.

                          e- C'est plus compliqué. Dans l'absolu, rien n'interdit aux compilos d'être plus intelligents que nous. Dans la pratique, on peut très bien repasser volontairement par une couche de void* si on préfère la factorisation de code. Ex: une voidList, dérivée par une List<> qui rajoute les cast par dessus. Ce qui permet de revenir à la solution du Java.
                          Mais bon, avec ce "void*"/super-objet à la Java nous sommes à des milliers de kilomètres de la généricité offerte par le C++. Les fonctions arg_min/max (std::min_element en C++) fonctionnent sur n'importe quelle séquence itérable (vecteur, tableau C, liste chainée, fichier, etc)

                          f- Tu veux parler d'héritage multiple d'interface ? Ben ... ce n'est qu'une juxtaposition de plusieurs vtables.
                          Ou pourquoi on râle après ceux qui viennent du C quand ils continuent d'utiliser les cast à la C au lieu de dynamic_cast là où l'on veut se déplacer à l'intérieur d'une hiérarchie. dynamic_cast applique les offsets qui vont bien (de même que le compilo dans le "simple" cas d'appel de fonction je pense).
                          Dans le cadre plus général de l'héritage multiple, il y a un très bon article explicatif qui vous donnera des indications quant à certains rouages (le Essential C++ de S.Lippman a longtemps été la référence sinon)
                          -> http://drdobbs.com/cpp/184402074

                          Citation : Terbaddo

                          g- J'avais pourtant vu un programme qui transforme un code C++ en C.


                          ... le premier compilo C++ -> CFront
                          Mais ne confondez pas LOO avec compilateur dont le rôle est de traduire depuis un langage vers un second. Ce n'est pas parce que le code dans le premier langage fait appel à des artifices fortement objets (ou autres comme la surcharge), que l'on va les retrouver dans le second langage.
                          Corolaire, le boulot que fait le compilo C++ concernant les vtables sur du MI devient apparent dans les langages cibles C/asm (selon la génération/approche du compilo C++)

                          Citation : ChristopheG

                          Pour moi,sur la question template / generic,

                          h- je dirais que la méthode java ou .net est clairement plus propre.

                          i- Le gros problème en c++ est l'absence de possibilité de specifier l'interface. Les compilateur font des remplacement pur et dur et en cas d'incompatibilité cela fait des messages d'erreurs incompréhensible et long de 4km.


                          h- C# et Java ont pourtant deux approches différentes, IIRC.

                          i- On aurait dû avoir les concepts, mais ils ont été écartés.
                          Il reste toujours la possibilité de rajouter des static_assert pour contraindre les paramètres et obtenir un message clair au milieu des 4km de messages -- et encore les compilos font de plus en plus d'efforts, cf clang.

                          Citation : QuentinC 2

                          j- Au fait ça m'amène à une question débile: pourquoi le C++ différencie-t-il delete et delete[] ? Quel est l'intérêt ? (Je ne parle pas de son utilisation mais bien de l'intérêt que ça a techniquement parlant... un bloc de mémoire est un bloc de mémoire)


                          j- Parce que ce n'est pas un bloc mémoire. C'est un ensemble d'éléments à détruire, et un bloc mémoire à libérer après.
                          Pour moi la question débile, c'est plutôt, mais pourquoi la nombre d'éléments ne leake pas (comme dans les leaking abstractions) automatiquement vu que quelques part il est connu.
                          Et donc dans le premier cas, on ne va pas vérifier derrière, et dynamiquement (vu que statiquement, c'est impossible. Pas besoin de détailler, hein ?), combien il y a d'éléments à détruire, on se contente juste du premier. -> retour à la sacro sainte règle C++ de ne pas payer ce que l'on utilise pas.

                          Citation : heizmann

                          k- un truc du genre : "Pensez Orienté Objet" :p ou un truc du genre, [...] Un truc qu'il faudrait éclaircir au risque de me répéter, serait qu'on puisse se mettre d'accord sur une façon "standard" de penser POO en C. Notamment en ce qui concerne le rôle que pourrait avoir le préprocesseur, et puis aussi préciser sur les mécanismes d'autogestion des VTables - si possible. :)


                          k- Oulah. Attention. Penser OO n'a rien à voir avec la technique (vtable, macros, etc).
                          C'est une des difficultés de l'enseignement historique du C++ d'ailleurs : on montrait un ensemble de mots clé et 3 termes (héritage, encapsulation, polymorphisme) et ... cela donnait n'importe quoi au final.
                          L'OO c'est un ensemble de concepts non techniques comme le LSP, la loi de Déméter, etc qui ne viennent pas forcément du monde OO au départ et pourtant il s'agit de vérités de l'approche OO.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                            3 mai 2011 à 5:48:17

                            Concernant, la technique, j'ai ceci dans mes favoris.

                            Méthode pour écrire du C orienté objet.

                            L'utilisation des vtables est différente de ce qu'a proposé Taurre(utilisation de offsetof), et on évite les void*.

                            C'est peut-être(peu être :-° ) intéressant à creuser. :)
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Zeste de Savoir, le site qui en a dans le citron !
                              3 mai 2011 à 6:21:50

                              Citation : GurneyH

                              Concernant, la technique, j'ai ceci dans mes favoris.

                              Méthode pour écrire du C orienté objet.

                              L'utilisation des vtables est différente de ce qu'a proposé Taurre(utilisation de offsetof), et on évite les void*.

                              C'est peu être intéressant à creuser. :)



                              ...ce qui me gène dans cette méthode est le fait qu'on fait de la manipulation de structures.

                              À propos, quelqu'un pourrait-il expliquer en termes simples ce qui diffère dans la pratique quant à l'utilisation du C (via la méthode présentée dans le lien posté par GurneyH) par rapport à la POO avec un LOO ? Je veux dire, en termes de maintenance, de solidité du code, de réutilisabilité etc. ? :) je serais curieux de voir ce qu'en pense les gens...

                              EDIT : quelques liens intéressants sur :

                              ...

                              ...la liste est longue (ouverture "(") mais a priori, comme on peut le constater, les anglosaxons sont souvent plus ouverts que nous en ce qui concerne l'OO en C (fermeture ")") :-°
                              • Partager sur Facebook
                              • Partager sur Twitter
                                3 mai 2011 à 11:26:57

                                Citation : heizmann

                                1- À propos, quelqu'un pourrait-il expliquer en termes simples ce qui diffère dans la pratique quant à l'utilisation du C (via la méthode présentée dans le lien posté par GurneyH) par rapport à la POO avec un LOO ? Je veux dire, en termes de maintenance, de solidité du code, de réutilisabilité etc. ? :) je serais curieux de voir ce qu'en pense les gens...

                                2- ...la liste est longue (ouverture "(") mais a priori, comme on peut le constater, les anglosaxons sont souvent plus ouverts que nous en ce qui concerne l'OO en C (fermeture ")") :-° </information>


                                2- Aucun rapport avec une quelconque ouverture. L'anglais est juste la langue des échanges dans notre métier. P.ex. la langue à maitriser pour progresser en C++, c'est l'anglais. Nous avons certes une communeauté active et pointue sur les divers forums fr (fclc++, dvpz), mais les articles fondateurs sont toujours en anglais, même si nous finissons par vous apporter en fr ce que nous avons glanné/échangé/pondu en anglais.

                                1- Plus de redondances, plus de lignes, donc plus de risques de se planter, donc maintenabilité fragilisée. (et cela ne vaut pas uniquement pour l'approche du lien de Gurney ; en recourant au void*, on fragilise le typage et on augmente les redondances)
                                Sauf architecture vraiment bridée et projets où je n'ai pas eu mon mot à dire, je n'ai plus aucune raison de me limiter au C, et de fait de procéder à des hacks visant à émuler des fonctionnalités qui sont natives dans d'autres langages.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                  3 mai 2011 à 11:40:17

                                  Citation : lmghs

                                  b- Les systèmes à GC se limitent à la mémoire.



                                  Ça tombe bien, 99% des "ressources" à gérer dans un programme, c'est de la mémoire. Et pour ça, quand t'as pas de GC, les destructeurs, c'est quand même bien.

                                  Citation : lmghs

                                  Ils ne comprennent rien aux autres ressources



                                  Ah le fameux "je laisse le GC fermer mon fichier" qu'on voit tout le temps en Python (le GC de CPython est déterministe) (mais pas celui de Jython, et autres... PAF !)

                                  Citation : lmghs

                                  Les destructeurs (on dit RAII, ou RRID en C++), c'est déterministe et implicite.



                                  Le RAII en C++ ne marche que partiellement, puisque nombre de ressources peuvent générer une erreur lors de leur libération (fichiers, sockets, etc) et qu'il est interdit de lever une exception dans un destructeur... Perso pour les vraies ressources, je préfère largement un truc à la "with" qui permet une gestion rigoureuse...

                                  > L'anglais est juste la langue des échanges dans notre métier.

                                  D'ailleurs il est difficile de trouver les quelques bon bouquins qui existent sur un sujet donné en Français... et accessoirement avec une traduction décente...

                                  > Plus de redondances, plus de lignes, donc plus de risques de se planter, donc maintenabilité fragilisée.

                                  +1

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    3 mai 2011 à 11:42:34

                                    De toute façon et pour reprendre le message d'au dessus :
                                    - Le C a encore beaucoup d'avantages par rapport à beaucoup de langages bien plus récents (maniabilité, souplesse, possibilités, facilité, etc...)
                                    - Les différents paradigmes ont été inventés par des gens très malins mais qui voulaient cibler un domaine. Les LOO ont fait exploser les jeux vidéos alors qu'un langage fonctionnel fortement typé comme OCaml a été très apprécié des mathématiciens (par exemple encore une fois)

                                    Ceci dit, il devient vite beaucoup plus simple de faire quelque chose de compliqué en C avec les bons outils (faire une appli Windows en C, ok, mais en C# ça prend quelques minutes).
                                    Les programmeurs de maintenant sont (comme ceux d'avant) souvent "amoureux" d'un langage, mais ils sont plus raisonnables quand il s'agit de son utilisation.

                                    Pour conclure : l'utilisation du C pour écrire du code avec une pensée objet est très faisable (et j'encourage même la pratique dans une idée didactique).
                                    L'utilisation de cette pratique, elle, n'est pas vraiment faisable. Le C++ (ne serait-ce que lui) fait tout ce qu'on voudrait faire en "C-Objet", plus facilement, et plus sûrement.

                                    Cependant notez bien que je ne critique pas du tout votre démarche, bien au contraire ! Cette idée m'intéresse.

                                    Quand j'ai appris le C, un ami programmeur m'a dit :"Le C peut simplement tout faire, dès que j'ai le choix c'est le langage que j'utilise."
                                    Quand plus tard j'ai vu d'autres langages de plus haut niveau (Java, C#, Windev(berk)), je me suis demandé "pourquoi tout faire en C alors qu'on fait mieux / plus vite avec d'autres langages (qui en plus ne sont pas incompatibles?"
                                    Aujourd'hui, je pense que faire quelque chose en C qui n'est pas du firmware ou du très bas niveau est difficile, mais pas plus "mauvais" que dans un autre langage. Un programmeur expérimenté ne verra pas la difficulté ;)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      3 mai 2011 à 11:47:20

                                      @lmghs & Lord Casque Noir :

                                      ;) mmhhh, merci pour ces éléments de réponses en tout cas ! Je marque une pose codage :-° en semaine pas trop le temps ^^ mais je reviens avec du code dès que possible, voilà !
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        3 mai 2011 à 16:13:22

                                        Citation : GurneyH


                                        Concernant, la technique, j'ai ceci dans mes favoris.

                                        Méthode pour écrire du C orienté objet.

                                        L'utilisation des vtables est différente de ce qu'a proposé Taurre(utilisation de offsetof), et on évite les void*.

                                        C'est peu être intéressant à creuser. :)



                                        Très intéressant ce lien, y pas mal d'idées intéressantes :)
                                        C'est juste dommage qu'il ne donne pas un main d'exemple histoire que l'on puisse voir comment il utilise ses structures. D'ailleurs, je n'ai pas bien compris comment il s'en sort lorsqu'il doit appeler une fonction de la structure mère et lui passer une structure fille en argument...

                                        Sinon, L'idée de rendre la définition de la structure vtable publique est franchement pas mal et permet d'éviter le double appel lors de l'utilisation des fonctions virtuelles (même si je pense que je préfère quand même ma méthode :-° ).

                                        Je me permet de reposter mon code corriger suivant les commentaires de QuentinC 2 et également inspiré du lien de GurneyH:


                                        personnage.h




                                        #ifndef PERSONNAGE_H
                                        #define PERSONNAGE_H  1
                                        
                                        #define PERSONNAGE_DEFINITION \
                                        	int vie; 
                                        
                                        #define PERSONNAGE_VTABLE \
                                        	void (*touche) (struct personnage *, int); \
                                        	void (*delete) (struct personnage *);
                                        
                                        
                                        struct personnage;
                                        typedef void personnage_s;
                                        
                                        struct personnage*
                                        personnage_create (struct personnage *self);
                                        
                                        void
                                        personnage_touche (struct personnage *self, int degats);
                                        
                                        int
                                        personnage_vie (struct personnage *self);
                                        
                                        void
                                        personnage_delete (struct personnage *self);
                                        
                                        
                                        #endif /* PERSONNAGE_H */
                                        




                                        personnage.c




                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        
                                        #include "personnage.h"
                                        
                                        
                                        struct personnage_vtable {
                                        	PERSONNAGE_VTABLE
                                        };
                                        
                                        
                                        struct personnage {
                                        	struct personnage_vtable *vtable;
                                        	PERSONNAGE_DEFINITION
                                        };
                                        
                                        
                                        static void
                                        touche (struct personnage *self, int degats)
                                        {
                                        	self->vie -= degats;
                                        }
                                        
                                        
                                        static void
                                        delete (struct personnage *self)
                                        {
                                        	free (self);
                                        	puts ("destruction d'un personnage");
                                        }
                                        
                                        
                                        struct personnage*
                                        personnage_create (struct personnage *self)
                                        {
                                        	static struct personnage_vtable vtable = {
                                        		.touche = touche,
                                        		.delete = delete
                                        	};
                                        
                                        	if (!self) {
                                        		if (!(self = malloc (sizeof *self))) {
                                        			return NULL;
                                        		}
                                        	}
                                        
                                        	self->vie = 100;
                                        	self->vtable = &vtable;
                                        
                                        	return self;
                                        }
                                        
                                        
                                        void
                                        personnage_touche (struct personnage *self, int degats)
                                        {
                                        	self->vtable->touche (self, degats);
                                        }
                                        
                                        
                                        int
                                        personnage_vie (struct personnage *self)
                                        {
                                        	return self->vie;
                                        }
                                        
                                        
                                        void
                                        personnage_delete (struct personnage *self)
                                        {
                                        	self->vtable->delete (self);
                                        }
                                        




                                        mage.h




                                        #ifndef MAGE_H
                                        #define MAGE_H  1
                                        
                                        
                                        #define MAGE_DEFINITION \
                                        	int mana;
                                        
                                        struct mage;
                                        typedef void mage_s;
                                        
                                        
                                        struct mage*
                                        mage_create (struct mage *self);
                                        
                                        
                                        #endif /* MAGE_H */
                                        




                                        mage.c




                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        
                                        #include "personnage.h"
                                        #include "mage.h"
                                        
                                        
                                        struct mage_vtable {
                                        	PERSONNAGE_VTABLE
                                        };
                                        
                                        
                                        struct mage {
                                        	struct mage_vtable *vtable;
                                        	PERSONNAGE_DEFINITION
                                        	MAGE_DEFINITION
                                        };
                                        
                                        
                                        static void
                                        touche (struct personnage *personnage, int degats)
                                        {
                                        	struct mage *self = (struct mage *)personnage;
                                        
                                        	self->vie -= (degats - (self->mana / 10));
                                        }
                                        
                                        
                                        static void
                                        delete (struct personnage *personnage)
                                        {
                                        	free (personnage);
                                        	puts ("destruction d'un mage");
                                        }
                                        
                                        
                                        struct mage*
                                        mage_create (struct mage *self)
                                        {
                                        	static struct mage_vtable vtable = {
                                        		.touche = touche,
                                        		.delete = delete
                                        	};
                                        
                                        	if (!self) {
                                        		if (!(self = malloc (sizeof *self))) {
                                        			return NULL;
                                        		}
                                        	}
                                        
                                        	personnage_create ((struct personnage *)self);
                                        	self->mana = 100;
                                        	self->vtable = &vtable;
                                        
                                        	return self;
                                        }
                                        




                                        main.c




                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        
                                        #include "personnage.h"
                                        #include "mage.h"
                                        
                                        
                                        
                                        int
                                        main (void)
                                        {
                                        	personnage_s *maurice;
                                        	mage_s *adalbert;
                                        
                                        	maurice = personnage_create (NULL);
                                        	adalbert = mage_create (NULL);
                                        
                                        	personnage_touche (maurice, 20);
                                        	personnage_touche (adalbert, 20);
                                        
                                        	printf ("maurice: %d\n", personnage_vie (maurice));
                                        	printf ("adalbert: %d\n", personnage_vie (adalbert));
                                        
                                        	personnage_delete (maurice);
                                        	personnage_delete (adalbert);
                                        
                                        	return EXIT_SUCCESS;
                                        }
                                        



                                        La vtable de chaque structure est désormais identique et statique, ce qui simplifie pas mal les allocations. Le constructeur alloue de la mémoire uniquement si on lui passe un pointeur nul en argument (ce qui évite l'appel à realloc de l'exemple précédent). Afin d'éviter des casts en cascade et l'utilisation abusive de pointeurs génériques dans les fonctions, les alias utilisé pour désigner les structures sont désormais void (et on utilise des pointeurs sur void dans la fonction main).

                                        A noter que j'ai laissé le destructeur virtuel même si c'est inutile :-°
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          3 mai 2011 à 19:03:55

                                          euh, y'en a qui connaissaient pas le lien de GurneyH ? :-° c'est l'un des premiers qu'on a en faisant des requêtes Google pourtant...
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            3 mai 2011 à 20:01:19

                                            Citation : heizmann


                                            euh, y'en a qui connaissaient pas le lien de GurneyH ? :-° c'est l'un des premiers qu'on a en faisant des requêtes Google pourtant...



                                            Je n'ai pas spécialement fait de recherche sur le sujet ;)
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              3 mai 2011 à 20:09:30

                                              ^^ c'est noté, Taurre, aucun souci :) et donc, euh ben bonne analyse de ce papelard fort intéressant alors ;)

                                              PS : de manière générale (ça s'adresse à tout le monde) vous trouvez des trucs intéressants aussi dans ce que je poste ? (cf mes liens ci-dessus)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                3 mai 2011 à 20:18:08

                                                Citation : heizmann


                                                PS : de manière générale (ça s'adresse à tout le monde) vous trouvez des trucs intéressants aussi dans ce que je poste ? (cf mes liens ci-dessus)



                                                Je ne les ai pas encore tous lu, mais l'astuce pour compter le nombre d'arguments d'une macro à nombres variables de paramètres est juste géniale! C'est ce genre d'astuce que j'adore ^^
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  3 mai 2011 à 20:33:01

                                                  Citation : Taurre

                                                  Citation : heizmann


                                                  PS : de manière générale (ça s'adresse à tout le monde) vous trouvez des trucs intéressants aussi dans ce que je poste ? (cf mes liens ci-dessus)



                                                  Je ne les ai pas encore tous lu, mais l'astuce pour compter le nombre d'arguments d'une macro à nombres variables de paramètres est juste géniale! C'est ce genre d'astuce que j'adore ^^



                                                  :p j'avoue que pour compter le nombre d'arguments d'une macro, L. Deniau a fait très fort :D

                                                  Exploitable par exemple pour rendre « portable » l'astuce du compilateur gnu :

                                                  "code non portable (compilo gnu)"
                                                  #define AFFICHE(format, ...) \
                                                  fprintf(stderr, "Erreur : " format, ##__VA_ARGS__);
                                                  

                                                  (Edit du code : y'avait une erreur ^^ )

                                                  (suffit de créer une petite macro comptant les variables, puis de faire une macro switch pour diriger soit vers une macro sans arguments optionnels, soit vers une macro ayant au moins un argument optionnel ;) ça permet de supprimer la virgule finale dans les cas où y'a pas d'arguments optionnels)

                                                  Autre idée : int printf(char *format, ...); a besoin de parser un format pour connaître le nombre d'arguments... en général, il faut connaître le nombre d'arguments à l'avance pour les fonctions variadiques. Ben avec cette astuce, on peut s'en passer désormais :p ! suffit de définir une macro qui "invoque la bonne fonction" en rajoutant par exemple le nombre d'arguments.

                                                  Exemple : transformer FOO("Message ", 2, i, compteur) en : FOO_BAR("Message ", 3, 2, i, compteur) (le "3" ajouté compte le nombre de variables derrière lui, à adapter selon les besoins bien entendu)

                                                  (la variable rajoutée renseignera les va_list, va_start et autres va_trucs de la biblio stdarg.h ^^ )
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    3 mai 2011 à 22:17:24

                                                    Citation : heizmann


                                                    À propos, regardez mes posts et mes codes les pages précédentes, le long de ce fil

                                                    @GurneyH



                                                    Tu peux aussi poster un message sur le forum fclc, Laurent Deniau y est un participant fidèle depuis de nombreuses années et je pense que si tu as des questions ou un problème motivé à poser, il te donnera son avis d'expert.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      4 mai 2011 à 13:27:34

                                                      Citation : candide

                                                      Citation : heizmann


                                                      À propos, regardez mes posts et mes codes les pages précédentes, le long de ce fil

                                                      @GurneyH



                                                      Tu peux aussi poster un message sur le forum fclc, Laurent Deniau y est un participant fidèle depuis de nombreuses années et je pense que si tu as des questions ou un problème motivé à poser, il te donnera son avis d'expert.



                                                      :waw: oooohh... :D génial, cette info ! Je crois que j'irai le voir en effet !!! :p Merci !!!
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        2 juin 2011 à 12:52:40

                                                        Je me permets de remonter le sujet, parce que je viens de tomber sur quelque chose d'assez intéressant. En effet, le brouillon de la future Norme C1X prévoit une nouvelle fonctionnalité du langage appelée "sélection générique" (Norme C1X, 6.5.1.1 p 78). En voici un exemple:

                                                        int entier = 10;
                                                        
                                                        _Generic (entier,
                                                                  int: abs,
                                                                  double: fabs,
                                                                  default: fabs) (entier);
                                                        


                                                        Suivant le type de la première expression, cette sélection sera remplacée par abs (entier) ou fabs (entier). Ces sélections sont notamment utilisée pour simplifier les appels des fonctions mathématique qui ont souvent trois versions pour les types float, double et long double (sans compter le support des nombres complexes pour certaines) avec des macro du style:

                                                        #define sqrt(X) _Generic ((X),                    \
                                                                                  float: sqrtf,           \
                                                                                  double: sqrt,           \
                                                                                  long double: sqrtl,     \
                                                                                  default: sqrt) (X)      \
                                                        


                                                        Un petit pas de plus du C vers la généricité :)
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          2 juin 2011 à 13:51:33

                                                          Sympa, en effet.
                                                          Ca peux permettre d'éviter pas mal de gymnastique. :-°

                                                          #include <stdio.h>
                                                          #include <stdlib.h>
                                                          #include <math.h>
                                                          
                                                          #define ABS(x, type)    type##_abs(x)
                                                          
                                                          int int_abs(int x){
                                                              return abs(x);
                                                          }
                                                          
                                                          
                                                          double double_abs(double x){
                                                              return fabs(x);
                                                          }
                                                          
                                                          
                                                          
                                                          int main(void){
                                                              double d = -0.152;
                                                              int i = -3;
                                                          
                                                              printf("%d\n", ABS(i, int));
                                                              printf("%f\n", ABS(d, double));
                                                          
                                                              return 0;
                                                          }
                                                          
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Zeste de Savoir, le site qui en a dans le citron !
                                                            2 juin 2011 à 14:29:14

                                                            D'autant que cela évite les typedef pour les types composés comme long double, long long ou encore pour les complexes :D
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            La POO et le C

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown