Vous m'avez sûrement déjà lu dans des posts tels que " je ne comprend pas si" ou "j'arrive pas à faire ça" ! Aujourd'hui je vais animer un débat que je trouve très intéressant pourquoi choisir la POO à la place du C (qui est tout sauf OO) ? Quels sont les différences majeurs entres ces deux "types" de programmation ? C'est ce à quoi nous allons essayer de répondre aujourd'hui !
Je vous remercie par avance de l'intérêt que vous porterez à ce message (sauf si vous passez votre chemin sans répondre )
La POO n'est qu'un paradigme, c'est a dire une manière de concevoir les choses, ce n'est pas un langage comme le C ou le C++.
Maintenant, pourquoi préférer la POO, c'est une question de goût je dirait.
En C, rien ne nous empêche de faire de la pseudo OO. Il suffit de voir comment est organisé FILE, SDL_Surface.
Erf, ça fonctionne pas. Ca n'a pas l'air d'être de l'OO tout ça !
Plutôt que parler OO pour FILE ou SDL_Surface (et encore SDL_Surface c'est faux) on parlera de structure opaque. FILE est opaque, SDL_Surface, non (enfin si, ya 1 champ dans SDL_Surface qui est opaque).
Avoue tu l'as fait exprès.
Ce que je voulais dire, c'est qu'on peut voir la notion de constructeur et de services, avec un découpage bien propre, le tout gravitant autour d'une structure.
On ne pourra pas facilement faire de la vrai POO en C car nativement, on a aucun des trois pilier de l'OO.
Pas d'héritage, pas d'encapsulation et encore moins de polymorphisme.
Alors après, par certains ruse, on peut simuler un bon semblant d'OO.
On peut même utiliser flex/bison pour aller plus loin, mais a ce stade, c'est presque faire son propre compilateur C++.
Pouet_forever : On peut très bien faire de l'OO en C et ce n'est pas parce que le langage n'inclue la possibilité de mettre des méthodes directement associé à la struct, que ce n'est pas orienté Objet.
Va dire aux mec de Gnome que tous le système GObject n'est pas de l'orienté objet ...
La question est idiote car elle oppose un langage à un paradigme.
Mais le langage n'intervient pas ici. On peut faire de l'objet en C comme on peut faire du procédural en C++. C'est juste une question de facilité offerte par le langage.
Merci pour vos réponses. Quand j'ai dit C c'était par ce que je ne connaissais pas le type de programmation "par défaut" de ce language (comme la POO l'est pour le java ou le C++) ! je ne connais d'ailleurs toujours pas son nom ! Ma question était donc : lequel de ce deux types de programmation est le plus utile ? Dans quel cas ? Quels sont les différences ?
Le C est plus adapté au paradigme procedural.
Mais il n'y a pas de type "par défaut", juste des facilité offerte ou non par le langage.
Après ça dépend du projet. Il n'y a pas de meilleurs ou de plus utile. la POO semble plus facile a gérer pour les gros projets que le procedural mais c'est vague, de très gros projets utilisent le C dans une approche clairement pas Objet.
Au final je pense que ça s'adapte aux sensibilité de chacun et au type d'application
Je serais curieux de voir ça !
Tu peux simuler de l'OO si tu veux, pas en faire.
Sympa, on peut faire du polymorphisme en C ! L'héritage, les classes, les attributs, les méthodes. On peut même faire "salut" + "toi". Cool !
Oui car je fais la différence entre l'orienté objet et la programmation objet pur.
Tu n'es pas obligé d'etre d'accord avec moi, je n'essais pas d'imposer ma vision, mais pour moi c'est la manière de programmer qui compte et pas le langage. Et si tu es capable de mettre en place certains mécanisme je considére que c'est de l'OO. Après que ces mécanisme soit intégré dans le langage (comme le c++) ou que tu les émules par des fonctions, macro et règles (comme avec le c + gobject), je ne vois pas trop la différence.
D'autant que certains langages sont clairement plus objet que le c++
Bonjour, semblerait-il que la question de vouloir "implémenter" les paradigmes de la POO en C refait surface ?
remarque moi j'ai rien contre, au contraire, je glane toutes les informations sur le net concernant le sujet, et personnellement, petit-à-petit, je commence à y voir un peu plus clair (mais vraiment petit à petit).
En clair, j'ai vu qu'on pouvait :
-faire de l'héritage (pas trop dur à implémenter)
-gérer les exceptions (avec une astuce du préprocesseur)
-plus dur : simuler la surcharge des méthodes (à coups de X-macros rusées et de macros à nombre variable de paramètres + struct + union (+ enum éventuellement pour la propreté du "code"))
encore plus casse-pieds mais faisable : résoudre le problème des droits d'accès (private/protected/public) (si si !) ; alors là je prends des risques parce que j'essaie de "résoudre" un conflit avec le problème de l'héritage en rapport avec cela, mais l'ADT semble être une solution à condition qu'il soit bien employé.
En fait, là où je bute (et a priori en parcourant la toile je suis loin d'être le seul) c'est tout ce qui gravite autour des droits d'accès aux attributs/membres d'une "pseudo" classe en C (avec une struct forcément)... 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.
Pour ma part, je tâche de voir comment résoudre les grands paradigmes de la POO en C. Et surtout essayer de tous les essayer en même temps.
À propos : pour les templates : moyen ou pas en C ? J'ai lu sur le net que ça serait possible avec le préprocesseur, mais pour ma part je crois que c'est assez bancal... en effet, peu de moyen de contrôle sur le typage (hormis utiliser des astuces non portables, comme le mot clé "typeof" accepté sur le compilo gcc).
À propos de gcc : ce compilo offre des possibilités intéressantes quant à l'utilisation du préprocesseur, malheureusement, on quitte la norme ANSI. Par exemple, il est possible de parser une macro à nombre variable de paramètres en prenant en compte le fait que cette dernière ne puisse avoir aucun argument facultatif. Exemple :
En plaçant "##" devant "__VA_ARGS__" ça aura pour effet de "supprimer" la dernière virgule si on ne met pas d'arguments facultatifs (essayez en ligne de commande par exemple avec un petit "gcc -E test.c").
@Malikemal : mmhhh... je peux peut-être écrire dans ce topic les différentes astuces que j'utilise pour faire "ma sauce POO-C" ? euh, juste pour éviter de surcharger le forum dans un premier temps ( plus simple pour s'y retrouver dans les messages !)
@heizmann : Pour moi, la grande partie de ce que tu fais n'a rien a voir avec la POO, c'est plus imiter le C++.
En effet les exceptions, les surcharges de méthodes et les templates n'ont rien a voir avoir la POO. Ce sont des éléments présents dans le C++ (entre autre) qui ne le sont pas dans le C, mais qui ne servent en aucun cas a faire de la POO.
Héritage et encapsulation oui, le reste de ce que tu cite non
-gérer les exceptions (avec une astuce du préprocesseur)
-plus dur : simuler la surcharge des méthodes (à coups de X-macros rusées et de macros à nombre variable de paramètres + struct + union (+ enum éventuellement pour la propreté du "code"))
encore plus casse-pieds mais faisable : résoudre le problème des droits d'accès (private/protected/public) (si si !) ; alors là je prends des risques parce que j'essaie de "résoudre" un conflit avec le problème de l'héritage en rapport avec cela, mais l'ADT semble être une solution à condition qu'il soit bien employé.
Je serai curieux de voir un programme faisant appel à toutes ces magouilles!
Avant de débattre sur un tel sujet commencer par dire ce qu'est la POO pour vous évitera beaucoup de malentendus, et des comparaisons du C à d'autres langages (comme dit plus haut).
En tout cas, si la POO pour vous consiste à regrouper les informations sur un même objet dans une seule instance, c'est bien évidemment une structure qui servira pour implémenter ce principe. Et si le C n'offre pas la possibilité de déclarer ou même de définir une fonction dans une structure, on peut utiliser un pointeur sur fonction.
Pour le polymorphisme, par principe deux objets en C (ayant la même portée) ne peuvent pas avoir le même identificateur (sauf si l'une est une déclaration et l'autre une définition, mais il n'y a pas de rapport avec le polymorphisme), donc c'est vite réglé, il vaut mieux oublier plutôt que de faire appel à des méthodes tirées par les cheveux ou de compter sur des extensions de compilateur. Pour l'histoire des pointeurs sur fonction, je ne suis pas d'accord avec vous, sauf pour la surcharge.
Pour les exceptions, si le but est de comparer C à C++, ce dernier gère les exceptions à l'exécution, or notre ami heizmann fait appel au préprocesseur, donc tu ne gères que les "exceptions" provoquées statiquement par ton programme. Et ce n'est pas ce qu'on appel une exception!
En C il est possible de gérer une exception à l'exécution d'un programme (à l'aides des fonctions de setjmp.h ou autre), mais c'est tellement usine-à-gaze qu'un if pour voir si l'information est valide ou pour checker errno suffit dans 99% des cas.
La surcharge par principe ne peut pas être implémenter en C (la raison est la même que pour le polymorphisme). Mais bien entendu on peut utiliser un pointeur sur fonction pour y arriver.
@PO :
En bref, C et C++ ne devraient pas être comparés; la POO peut être implémentée en C jusqu'à un certain point, après le code devient horrible.
On peut faire de la POO en C, mais en général, c'est très sale.
Soit, une classe Classe contenant un attribut intTruc avec les getters et setters getTruc et setTruc respectivement,
typedef struct { int Truc; } Classe;
int getTruc(Classe classe);
void setTruc(Classe classe, int truc);
Classe classe;
int truc = getTruc(classe);
truc++;
setTruc(classe, truc);
Quand je dis que c'est sale c'est pas pour rien. Et encore, c'est pas tout ! Y a ni constructeur, ni héritage, juste un attribut int, un getter et un setter.
class Classe {
public:
int getTruc() const;
void setTruc(int truc);
private:
int truc;
}
Classe classe;
int truc = classe.getTruc();
truc++;
classe.setTruc(truc);
Oui enfin ton don exemple C tu as le droit de mettre des pointeurs pour ta "Classe" dans les fonctions car sinon le setter ne feras pas grand chose
Sinon J'ai juste dit que c'étais possible, pas que c'étais propre.
Et l'héritage, suffit de mettre en premier terme de ta struct une autre struct et tu l'a ta classe de base. En castant les pointeur tu pourras accéder aux membres interne de la classe de base (mais il faut que ce soit le premier élément de la nouvelle classe)
Je serai curieux de voir un programme faisant appel à toutes ces magouilles!
+1, je veux bien voir aussi
Citation : uknow
Pour le polymorphisme, par principe deux objets en C (ayant la même portée) ne peuvent pas avoir le même identificateur (sauf si l'une est une déclaration et l'autre une définition, mais il n'y a pas de rapport avec le polymorphisme), donc c'est vite réglé, il vaut mieux oublier plutôt que de faire appel à des méthodes tirées par les cheveux ou de compter sur des extensions de compilateur. Pour l'histoire des pointeurs sur fonction, je ne suis pas d'accord avec vous, sauf pour la surcharge.
Quand je parlais de polymorphisme, je parlais de celui présenté par Nanoc comme le "polymorphisme paramétrique", c'est à dire le fait qu'un code puisse travailler avec n'importe quel type de donnée. Ce qui est bien le cas de la fonction qsort
Citation : Terbaddo
On peut faire de la POO en C, mais en général, c'est très sale.
[...]
Ce que tu montres correspond à de la programmation modulaire, si ce n'est qu'en théorie on travail avec des TAD (type abastrait de donnée). Or, c'est sans aucun doute la manière la plus propre d'utiliser une approche OO en C.
Sans vouloir me relancer une fois de plus de débat (on devrait en mettre un en post-it pour s'en débarrasser, voir le caser dans la FAQ), j'ai juste envie de souligner qu'ici on confond "être propre" et "avoir la même syntaxe que le C++". Le gros inconvénient du polymorphisme en C, c'est que les compilateurs font des checks de cohérence des types qui vont générer des warnings tout le temps. Le fait que l'outil utilisé ne soit pas pensé pour une utilisation donnée n'implique pas nécessairement que le travail effectué est sale (c'est là dessus que se base la culture hacker depuis plus d'un siècle (même si elle ne portait pas ce nom à l'époque, mais, encore une fois, ce n'est qu'un nom))
Quand je parlais de polymorphisme, je parlais de celui présenté par Nanoc comme le "polymorphisme paramétrique", c'est à dire le fait qu'un code puisse travailler avec n'importe quel type de donnée. Ce qui est bien le cas de la fonction qsort
Je dirai que c'est de la surcharge car la fonction aura la même signature (donc les mêmes arguments).
Je dirai que c'est de la surcharge car la fonction aura la même signature (donc les mêmes arguments).
Je n'ai pas bien suivi ton raisonnement... la fonction qsort reçoit toujours le même type d'arguments, il n'y a donc pas de surcharge, si?
Pour moi l'exemple type de surcharge de fonction en C ce sont les fonctions à nombre variables d'arguments, comme printf ou ioctl de l'interface POSIX par exemple. Certes il n'y a pas d'appel à des fonctions différentes suivant le type des arguments, mais la fonction a différents comportements suivant le type de ses arguments.
Je n'ai pas bien suivi ton raisonnement... la fonction qsort reçoit toujours le même type d'arguments, il n'y a donc pas de surcharge, si?
Je vois qu'on est d'accord , c'est de ma faute j'aurais dû parler de redéfinition plutôt que de surcharge (deux notions très liées en JAVA; un peu moins en C++ et c'est de là que vient mon erreur).
Quand je parlais de polymorphisme, je parlais de celui présenté par Nanoc comme le "polymorphisme paramétrique", c'est à dire le fait qu'un code puisse travailler avec n'importe quel type de donnée. Ce qui est bien le cas de la fonction qsort
Quand les gens parlent de polymorphisme, surtout quand le contexte OO est présent, il s'agit du polymorphisme d'inclusion (dit encore d'héritage).
Le polymorphisme paramétrique est l'autre polymorphisme universel, et il n'a rien d'OO. http://cpp.developpez.com/faq/cpp/?pag [...] polymorphisme
À ce propos s'il y a un truc propre à l'OO qui fait que c'est vraiment OO, et pas juste du sucrage syntaxique, c'est ce fameux polymorphisme d'inclusion. Abstraction (et son avatar OO d'encapsulation) et héritage sont faciles à émuler, même en C.
Le polymorphisme demande plus d'huile de coude. COS (qui a été évoqué) le permet. Il permet même un polymorphisme que les langages OO mainstream (C++, Java, ...) ne supportent pas facilement, le multi-dispatch si mes souvenirs sont exacts.
Citation : uknow
c'est de ma faute j'aurais dû parler de redéfinition plutôt que de surcharge (deux notions très liées en JAVA; un peu moins en C++ et c'est de là que vient mon erreur).
Surcharge (overloading) et redéfinition (overidding) sont exactement la même chose en C++ et en Java. L'un des deux polymorphisme ad'hoc pour la surcharge, un sucre syntaxique. Le moyen de mettre en œuvre une liaison tardive/dynamique dans le cadre du polymorphisme d'inclusion pour le second.
Pour vos exemples, printf s'apparente plus à du polymorphisme paramétrique dans la mesure où il accepterait une infinité de types d'argument (quoiqu'ils sont nécessairement POD et donc in fine limités en nombre :/)
PS: je confirme au passage qu'exceptions et surcharge n'ont rien d'OO.
-gérer les exceptions (avec une astuce du préprocesseur)
-plus dur : simuler la surcharge des méthodes (à coups de X-macros rusées et de macros à nombre variable de paramètres + struct + union (+ enum éventuellement pour la propreté du "code"))
encore plus casse-pieds mais faisable : résoudre le problème des droits d'accès (private/protected/public) (si si !) ; alors là je prends des risques parce que j'essaie de "résoudre" un conflit avec le problème de l'héritage en rapport avec cela, mais l'ADT semble être une solution à condition qu'il soit bien employé.
Je serai curieux de voir un programme faisant appel à toutes ces magouilles!
Avant de débattre sur un tel sujet commencer par dire ce qu'est la POO pour vous évitera beaucoup de malentendus, et des comparaisons du C à d'autres langages (comme dit plus haut).
En tout cas, si la POO pour vous consiste à regrouper les informations sur un même objet dans une seule instance, c'est bien évidemment une structure qui servira pour implémenter ce principe. Et si le C n'offre pas la possibilité de déclarer ou même de définir une fonction dans une structure, on peut utiliser un pointeur sur fonction.
Pour le polymorphisme, par principe deux objets en C (ayant la même portée) ne peuvent pas avoir le même identificateur (sauf si l'une est une déclaration et l'autre une définition, mais il n'y a pas de rapport avec le polymorphisme), donc c'est vite réglé, il vaut mieux oublier plutôt que de faire appel à des méthodes tirées par les cheveux ou de compter sur des extensions de compilateur. Pour l'histoire des pointeurs sur fonction, je ne suis pas d'accord avec vous, sauf pour la surcharge.
Pour les exceptions, si le but est de comparer C à C++, ce dernier gère les exceptions à l'exécution, or notre ami heizmann fait appel au préprocesseur, donc tu ne gères que les "exceptions" provoquées statiquement par ton programme. Et ce n'est pas ce qu'on appel une exception!
En C il est possible de gérer une exception à l'exécution d'un programme (à l'aides des fonctions de setjmp.h ou autre), mais c'est tellement usine-à-gaze qu'un if pour voir si l'information est valide ou pour checker errno suffit dans 99% des cas.
La surcharge par principe ne peut pas être implémenter en C (la raison est la même que pour le polymorphisme). Mais bien entendu on peut utiliser un pointeur sur fonction pour y arriver.
@PO :
En bref, C et C++ ne devraient pas être comparés; la POO peut être implémentée en C jusqu'à un certain point, après le code devient horrible.
vraiment une très intéressante lecture, en tout cas ! Alors je suis parfaitement d'accord avec vous, il faut déjà régler le problème de ce qu'on appelle POO. Pour moi, POO n'est pas à confondre avec LOO (Langage Orienté Objet), évidemment.
Puis, la POO : c'est un paradigme de programmation ; il est possible a priori d'implémenter ce paradigme plus ou moins à la lettre dans n'importe quel langage. Ce paradigme comprend (non exhaustif) dans les grandes lignes :
-l'encapsulation (attributs et membres) ;
-l'héritage ;
-le polymorphisme.
Ensuite, en ce qui concerne le C : j'essaie (par quelques acrobaties certes) de me rapprocher au maximum de ce paradigme. Évidemment, c'est assez pénible, car pour avoir un code le respectant il faut faire beaucoup de mallocs (un truc que j'utilise pour privatiser mes attributs). Ensuite, il y a le problème de la portabilité, donc interdiction de faire des `void *' par exemple, et bien contrôler des casts (le compilo est assez rigide par rapport au type des pointeurs ).
La surcharge : d'accord avec vous tous, ça n'a rien d'OO... mais c'est si pratique, autant `l'émuler' aussi en C...
Pour un exemple implémentant ma plaidoirie : un peu de patience... j'avais fait il y a quelques temps un programme gérant un peu la POO en C. Seulement j'ai perdu ce programme suite à un crash ça prend un peu de temps à réécrire...
@ lmghs & Taurre : mmhhh... intéressant, cette distinction de polymorphisme. Je n'y avais jamais songé (faut dire que j'ai malheureusement toujours programmé façon procédurale, la POO c'est assez nouveau pour moi). En clair, le polymorphisme d'inclusion c'est un polymorphisme qui permet de `deviner' si on est dans la classe mère ou fille, c'est bien cela ?
Le polymorphisme d'inclusion est le "polymorphisme-tout-court" de la litérature OO.
C'est celui qui fait que l'on puisse dire à un truc-qui-sait-rouler de rouler(), les trucs sachant rouler appartenant tous à une même et grande famille. Le comment on y arrive, c'est via l'héritage (public en C++). On peut exploiter la résolution dynamique des liens (fonctions virtuelles) pour atteindre des comportements spécialisés, mais parfois ce n'est pas nécessaire (p.ex. le code pour parcourir deux structures chainées itérables, qu'elles soient triées ou non, sera toujours le même)
Ce n'est pas une question de savoir où l'on est, mais de faire ce qui doit l'être. C'est pas pareil.
Quand les gens parlent de polymorphisme, surtout quand le contexte OO est présent, il s'agit du polymorphisme d'inclusion (dit encore d'héritage).
Le polymorphisme paramétrique est l'autre polymorphisme universel, et il n'a rien d'OO.
Oui, j'aurais dû parler de programmation générique, cela porte nettement moins à confusion.
Citation : heizmann
Ensuite, il y a le problème de la portabilité, donc interdiction de faire des `void *' par exemple
En quoi l'utilisation d'un pointeur sur void n'est-elle pas portable? Ils ont été introduit par la Norme C89, j'espère bien que leur utilisation est portable!
Ensuite, il y a le problème de la portabilité, donc interdiction de faire des `void *' par exemple
En quoi l'utilisation d'un pointeur sur void n'est-elle pas portable? Ils ont été introduit par la Norme C89, j'espère bien que leur utilisation est portable!
Ah ben autant pour moi alors... peut-être, pour la portabilité des void*... a priori, cela n'est pas portable, selon un tuto du SdZ. Maintenant, si effectivement l'utilisation des void* est portable à partir de la norme C89... je me renseigne pour les prochains jours alors
Bon en tout cas pour mon implémentation d'objets en C, ça avance... quelqu'un pourra-t-il me dire si le(s) paradigme(s) sont correctement implantés une fois que je fournirai ici même du code source ? ça me permettra de voir si ma façon de coder est correct ou non.
En tout cas, la plupart de mes bouts de code semblent fonctionner correctement. Tout est dynamique. J'ai laissé tomber l'utilisation à outrance du préprocesseur, je compte m'en servir uniquement pour décrire mes classes à coups de X-macros, mais ça ce sera une fois que j'aurai réussi à implanter quelque chose de consistant.
Pour ceux qui me diraient : « c'est bien joli, mais pour faire de la POO, utilise un LOO », je leur réponds : « mmhhh, oui, c'est certain, cela dit implémenter de l'OO en C a une vertu pédagogique certaine, et puis c'est un excellent exercice, je pense, pour apprendre à exploiter les possibilités du C ». Évidemment, le codage est lourdingue, et de ce fait, difficilement exploitable en industrie (généricité du code, entre autres). Mais bon, si je reste dans une optique pédagogique...
× 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.
Objectif Zéro Bug - le test logiciel professionnel | L'électronique de zéro | Tableaux & pointeurs | Pointeurs sur fonctions | Lecture/écriture binaire
Objectif Zéro Bug - le test logiciel professionnel | L'électronique de zéro | Tableaux & pointeurs | Pointeurs sur fonctions | Lecture/écriture binaire
Objectif Zéro Bug - le test logiciel professionnel | L'électronique de zéro | Tableaux & pointeurs | Pointeurs sur fonctions | Lecture/écriture binaire