Quels sont les moyens d'écrire du code orienté objet en C? Surtout en ce qui concerne le polymorphisme.
Voir aussi cette question Stack Overflow orienté objet en C .
Quels sont les moyens d'écrire du code orienté objet en C? Surtout en ce qui concerne le polymorphisme.
Voir aussi cette question Stack Overflow orienté objet en C .
Réponses:
Oui. En fait, Axel Schreiner fournit gratuitement son livre "Programmation orientée objet en ANSI-C" qui couvre le sujet de manière assez approfondie.
la source
Puisque vous parlez de polymorphisme, alors oui, vous pouvez, nous faisions ce genre de choses des années avant la création de C ++.
Fondamentalement, vous utilisez un
struct
pour contenir à la fois les données et une liste de pointeurs de fonction pour pointer vers les fonctions pertinentes pour ces données.Ainsi, dans une classe de communication, vous auriez un appel ouvert, lu, écrit et fermé qui serait maintenu comme quatre pointeurs de fonction dans la structure, à côté des données pour un objet, quelque chose comme:
Bien sûr, ces segments de code ci-dessus seraient en fait dans un "constructeur" tel que
rs232Init()
.Lorsque vous «héritez» de cette classe, vous changez simplement les pointeurs pour pointer vers vos propres fonctions. Tous ceux qui ont appelé ces fonctions le feraient via les pointeurs de fonction, vous donnant votre polymorphisme:
Un peu comme une table manuelle.
Vous pouvez même avoir des classes virtuelles en définissant les pointeurs sur NULL - le comportement serait légèrement différent de C ++ (un vidage de mémoire au moment de l'exécution plutôt qu'une erreur au moment de la compilation).
Voici un exemple de code qui le démontre. Tout d'abord la structure de classe de niveau supérieur:
Ensuite, nous avons les fonctions de la «sous-classe» TCP:
Et le HTTP aussi:
Et enfin un programme de test pour le montrer en action:
Cela produit la sortie:
vous pouvez donc voir que les différentes fonctions sont appelées, selon la sous-classe.
la source
tCommClass
serait renommétCommVT
, et unetCommClass
structure n'aurait que des champs de données et un seultCommVT vt
champ pointant vers la "seule et unique" table virtuelle. Porter tous les pointeurs autour de chaque instance ajoute une surcharge inutile et ressemble plus à la façon dont vous feriez des choses en JavaScript qu'à C ++, à mon humble avis.Les espaces de noms se font souvent en faisant:
au lieu de
Pour transformer une structure C en quelque chose comme une classe C ++ , vous pouvez activer:
Dans
Et fait:
Je n'ai pas fait le destructeur ni supprimé, mais il suit le même schéma.
this_is_here_as_an_example_only est comme une variable de classe statique - partagée entre toutes les instances d'un type. Toutes les méthodes sont vraiment statiques, sauf que certaines prennent ceci *
la source
st->my_type->push(st, thing2);
au lieu dest->my_type.push(st, thing2);
struct stack_type my_type;
au lieu destruct stack_type * my_type;
Class
structure générique ? Cela rendrait l'OO C plus dynamique que C ++. Et ça? Au fait, +1.Je crois qu'en plus d'être utile en soi, la mise en œuvre de la POO en C est un excellent moyen d' apprendre la POO et de comprendre son fonctionnement interne. L'expérience de nombreux programmeurs a montré que pour utiliser une technique de manière efficace et en toute confiance, un programmeur doit comprendre comment les concepts sous-jacents sont finalement mis en œuvre. L'émulation des classes, de l'héritage et du polymorphisme en C enseigne exactement cela.
Pour répondre à la question d'origine, voici quelques ressources qui enseignent comment faire la POO en C:
Le billet de blog d'EmbeddedGurus.com "Programmation basée sur les objets en C" montre comment implémenter les classes et l'héritage unique dans le C portable: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c /
La note d'application "" C + "- Programmation orientée objet en C" montre comment implémenter les classes, l'héritage unique et la liaison tardive (polymorphisme) en C à l'aide de macros de préprocesseur: http://www.state-machine.com/resources/cplus_3. 0_manual.pdf , l'exemple de code est disponible sur http://www.state-machine.com/resources/cplus_3.0.zip
la source
Je l'ai vu faire. Je ne le recommanderais pas. C ++ a commencé à l'origine de cette façon en tant que préprocesseur qui a produit du code C comme étape intermédiaire.
Essentiellement, vous finissez par créer une table de répartition pour toutes vos méthodes où vous stockez vos références de fonction. Dériver une classe impliquerait de copier cette table de répartition et de remplacer les entrées que vous vouliez remplacer, vos nouvelles "méthodes" devant appeler la méthode d'origine si elle voulait invoquer la méthode de base. Finalement, vous finissez par réécrire C ++.
la source
glib
écrit en C de manière objective?Bien sûr que c'est possible. C'est ce que fait GObject , le framework sur lequel GTK + et GNOME sont basés.
la source
La sous-bibliothèque C stdio FILE est un excellent exemple de la façon de créer l'abstraction, l'encapsulation et la modularité en C. non altéré.
L'héritage et le polymorphisme - les autres aspects souvent considérés comme essentiels à la POO - n'apportent pas nécessairement les gains de productivité qu'ils promettent et des arguments raisonnables ont été avancés selon lesquels ils peuvent réellement entraver le développement et la réflexion sur le domaine problématique.
la source
Exemple trivial avec un animal et un chien: vous reflétez le mécanisme vtable de C ++ (en grande partie de toute façon). Vous séparez également l'allocation et l'instanciation (Animal_Alloc, Animal_New) afin que nous n'appelions pas malloc () plusieurs fois. Nous devons également passer explicitement le
this
pointeur.Si vous deviez faire des fonctions non virtuelles, c'est trival. Vous ne les ajoutez tout simplement pas aux fonctions vtable et statiques ne nécessitent pas de
this
pointeur. L'héritage multiple nécessite généralement plusieurs vtables pour résoudre les ambiguïtés.De plus, vous devriez pouvoir utiliser setjmp / longjmp pour gérer les exceptions.
PS. Ceci est testé sur un compilateur C ++, mais il devrait être facile de le faire fonctionner sur un compilateur C.
la source
typedef
l'intérieur d'unstruct
n'est pas possible en C.Découvrez GObject . Il est censé être OO en C et une implémentation de ce que vous recherchez. Si vous voulez vraiment OO, optez pour C ++ ou un autre langage OOP. Il peut être parfois difficile de travailler avec GObject si vous avez l'habitude de gérer les langages OO, mais comme tout, vous vous habituerez aux conventions et au flux.
la source
Cela a été intéressant à lire. J'ai moi-même réfléchi à la même question, et les avantages d'y penser sont les suivants:
Essayer d'imaginer comment implémenter des concepts OOP dans un langage non-OOP m'aide à comprendre les points forts du langage OOp (dans mon cas, C ++). Cela m'aide à mieux juger de l'utilisation du C ou du C ++ pour un type d'application donné - où les avantages de l'un l'emportent sur l'autre.
Dans ma navigation sur le Web pour obtenir des informations et des opinions à ce sujet, j'ai trouvé un auteur qui écrivait du code pour un processeur intégré et n'avait qu'un compilateur C disponible: http://www.eetimes.com/discussion/other/4024626/Object-Oriented -C-Création-Fondation-Classes-Part-1
Dans son cas, l'analyse et l'adaptation des concepts de POO en simple C était une poursuite valable. Il semble qu'il était prêt à sacrifier certains concepts de POO en raison du dépassement des performances résultant de la tentative de les implémenter en C.
La leçon que j'ai tirée est, oui, cela peut être fait dans une certaine mesure, et oui, il y a de bonnes raisons de l'essayer.
En fin de compte, la machine tourne des bits de pointeur de pile, faisant sauter le compteur de programme et calculant les opérations d'accès à la mémoire. Du point de vue de l'efficacité, moins ces calculs sont effectués par votre programme, mieux c'est ... mais parfois nous devons payer cette taxe simplement pour pouvoir organiser notre programme de manière à le rendre moins vulnérable aux erreurs humaines. Le compilateur de langage OOP s'efforce d'optimiser les deux aspects. Le programmeur doit être beaucoup plus prudent lors de la mise en œuvre de ces concepts dans un langage comme C.
la source
Il peut être utile de consulter la documentation d'Apple pour son ensemble d'API Core Foundation. Il s'agit d'une pure API C, mais de nombreux types sont pontés vers des équivalents d'objet Objective-C.
Vous pouvez également trouver utile de regarder la conception d'Objective-C lui-même. C'est un peu différent de C ++ en ce que le système objet est défini en termes de fonctions C, par exemple
objc_msg_send
pour appeler une méthode sur un objet. Le compilateur traduit la syntaxe entre crochets en ces appels de fonction, vous n'avez donc pas besoin de la connaître, mais compte tenu de votre question, vous trouverez peut-être utile d'apprendre comment cela fonctionne sous le capot.la source
Il existe plusieurs techniques qui peuvent être utilisées. Le plus important est davantage de savoir comment diviser le projet. Nous utilisons une interface dans notre projet qui est déclarée dans un fichier .h et l'implémentation de l'objet dans un fichier .c. La partie importante est que tous les modules qui incluent le fichier .h ne voient qu'un objet en tant que a
void *
, et le fichier .c est le seul module qui connaît les éléments internes de la structure.Quelque chose comme ça pour une classe que nous nommons FOO comme exemple:
Dans le fichier .h
Le fichier d'implémentation C sera quelque chose comme ça.
Je donne donc le pointeur explicitement à un objet pour chaque fonction de ce module. Un compilateur C ++ le fait implicitement, et en C nous l'écrivons explicitement.
J'utilise vraiment
this
dans mes programmes, pour m'assurer que mon programme ne compile pas en C ++, et il a la belle propriété d'être dans une autre couleur dans mon éditeur de coloration syntaxique.Les champs du FOO_struct peuvent être modifiés dans un module et un autre module n'a même pas besoin d'être recompilé pour être toujours utilisable.
Avec ce style, je gère déjà une grande partie des avantages de la POO (encapsulation de données). En utilisant des pointeurs de fonction, il est même facile d'implémenter quelque chose comme l'héritage, mais honnêtement, ce n'est vraiment que rarement utile.
la source
typedef struct FOO_type FOO_type
place d'un typedef à annuler dans l'en-tête, vous obtenez l'avantage supplémentaire de la vérification de type, tout en n'exposant pas votre structure.Vous pouvez le simuler en utilisant des pointeurs de fonction, et en fait, je pense qu'il est théoriquement possible de compiler des programmes C ++ en C.
Cependant, il est rarement logique d'imposer un paradigme à une langue plutôt que de choisir une langue qui utilise un paradigme.
la source
C orienté objet, peut être fait, j'ai vu ce type de code en production en Corée, et c'était le monstre le plus horrible que j'avais vu depuis des années (c'était comme l'année dernière (2007) que j'ai vu le code). Alors oui, cela peut être fait, et oui, les gens l'ont déjà fait, et le font encore de nos jours. Mais je recommanderais C ++ ou Objective-C, les deux sont des langages nés de C, dans le but de fournir une orientation d'objet avec différents paradigmes.
la source
Si vous êtes convaincu qu'une approche POO est supérieure pour le problème que vous essayez de résoudre, pourquoi tenteriez-vous de le résoudre avec un langage non POO? Il semble que vous n'utilisiez pas le bon outil pour le travail. Utilisez C ++ ou un autre langage variant C orienté objet.
Si vous demandez parce que vous commencez à coder sur un grand projet déjà existant écrit en C, alors vous ne devriez pas essayer de forcer vos propres paradigmes de POO (ou ceux de quelqu'un d'autre) dans l'infrastructure du projet. Suivez les directives qui sont déjà présentes dans le projet. En général API, propres et les bibliothèques et les modules isolés vont un long chemin vers avoir un OOP- propre ish design.
Si, après tout cela, vous êtes vraiment prêt à faire de la POO C, lisez ceci (PDF).
la source
Oui, vous pouvez. Les gens écrivaient du C orienté objet avant que C ++ ou Objective-C n'entrent en scène. C ++ et Objective-C étaient, en partie, des tentatives de prendre certains des concepts OO utilisés en C et de les formaliser dans le cadre du langage.
Voici un programme très simple qui montre comment vous pouvez créer quelque chose qui ressemble à / est un appel de méthode (il existe de meilleures façons de le faire. C'est juste la preuve que le langage prend en charge les concepts):
la source
Bien sûr, ce ne sera pas aussi joli que d'utiliser un langage avec un support intégré. J'ai même écrit "assembleur orienté objet".
la source
Un petit code OOC à ajouter:
la source
Je creuse ça depuis un an:
Comme le système GObject est difficile à utiliser avec du C pur, j'ai essayé d'écrire de belles macros pour faciliter le style OO avec C.
Voici mon site de projet (je n'ai pas assez de temps pour écrire en. Doc, cependant la doc en chinois est bien meilleure).
OOC-GCC
la source
Il est un exemple d'héritage en C en 1996 parler de Jim Larson donné à la Section 312 Programmation Séminaire midi ici: haut et bas niveau C .
la source
Les interfaces et implémentations C de Dave Hanson sont excellentes pour l'encapsulation et la dénomination et très bonnes pour l'utilisation des pointeurs de fonction. Dave n'essaie pas de simuler l'héritage.
la source
La POO n'est qu'un paradigme qui place les données plus importantes que le code dans les programmes. La POO n'est pas une langue. Ainsi, comme le C simple est un langage simple, la POO en C simple est également simple.
la source
Une chose que vous voudrez peut-être faire est d'examiner la mise en œuvre de la boîte à outils Xt pour X Window . Bien sûr, cela prend du temps dans la dent, mais la plupart des structures utilisées ont été conçues pour fonctionner de manière OO dans le C. traditionnel.Généralement, cela signifie ajouter une couche supplémentaire d'indirection ici et là et concevoir des structures à superposer.
Vous pouvez vraiment faire beaucoup de choses sur la façon dont OO situé en C de cette façon, même si cela en a parfois l'air, les concepts OO ne sont pas complètement nés de l'esprit de
#include<favorite_OO_Guru.h>
. Ils constituaient vraiment bon nombre des meilleures pratiques établies de l'époque. Les langages et systèmes OO ne distillent et n'amplifient que des parties de la programmation du jour.la source
La réponse à la question est «Oui, vous le pouvez».
Le kit C orienté objet (OOC) est destiné à ceux qui souhaitent programmer de manière orientée objet, mais il colle également au bon vieux C. OOC implémente les classes, l'héritage simple et multiple, la gestion des exceptions.
Caractéristiques
• Utilise uniquement des macros et des fonctions C, aucune extension de langue requise! (ANSI-C)
• Code source facile à lire pour votre application. On a pris soin de rendre les choses aussi simples que possible.
• Héritage unique des classes
• Héritage multiple par interfaces et mixins (depuis la version 1.3)
• Implémentation d'exceptions (en C pur!)
• Fonctions virtuelles pour les classes
• Outil externe pour une implémentation de classe facile
Pour plus de détails, visitez http://ooc-coding.sourceforge.net/ .
la source
Il semble que les gens essaient d'émuler le style C ++ en utilisant C. Mon point de vue est que faire de la programmation orientée objet C fait vraiment de la programmation orientée struct. Cependant, vous pouvez réaliser des choses comme la liaison tardive, l'encapsulation et l'héritage. Pour l'héritage, vous définissez explicitement un pointeur vers les structures de base dans votre sous-structure et c'est évidemment une forme d'héritage multiple. Vous devrez également déterminer si votre
compiler avec
c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj
.Le conseil est donc de s'en tenir à un style C pur et de ne pas essayer de forcer dans un style C ++. De plus, cette méthode se prête à une manière très propre de créer une API.
la source
Voir http://slkpg.byethost7.com/instance.html pour encore une autre torsion sur la POO en C. Il met l'accent sur les données d'instance pour la réentrance en utilisant uniquement le C. natif. L'héritage multiple se fait manuellement à l'aide de wrappers de fonction. La sécurité du type est maintenue. Voici un petit échantillon:
la source
Je suis un peu en retard à la fête, mais je veux partager mon expérience sur le sujet: je travaille avec des trucs embarqués de nos jours, et le seul compilateur (fiable) que j'ai est C, donc je veux appliquer une approche orientée objet approche dans mes projets embarqués écrits en C.
La plupart des solutions que j'ai vues jusqu'à présent utilisent fortement les typecasts, nous perdons donc la sécurité des types: le compilateur ne vous aidera pas si vous faites une erreur. C'est totalement inacceptable.
Exigences que j'ai:
J'ai expliqué mon approche en détail dans cet article: Programmation orientée objet en C ; de plus, il existe un utilitaire pour la génération automatique de code passe-partout pour les classes de base et dérivées.
la source
J'ai construit une petite bibliothèque où j'ai essayé ça et pour moi ça marche vraiment bien. J'ai donc pensé partager l'expérience.
https://github.com/thomasfuhringer/oxygen
L'héritage unique peut être implémenté assez facilement en utilisant une structure et en l'étendant pour toutes les autres classes enfants. Un simple cast vers la structure parent permet d'utiliser des méthodes parents sur tous les descendants. Tant que vous savez qu'une variable pointe vers une structure contenant ce type d'objet, vous pouvez toujours transtyper vers la classe racine et effectuer une introspection.
Comme cela a été mentionné, les méthodes virtuelles sont quelque peu plus délicates. Mais ils sont réalisables. Pour garder les choses simples, j'utilise simplement un tableau de fonctions dans la structure de description de classe que chaque classe enfant copie et repeuple les emplacements individuels si nécessaire.
L'héritage multiple serait plutôt compliqué à implémenter et aurait un impact significatif sur les performances. Je le laisse donc. Je considère qu'il est souhaitable et utile dans de nombreux cas de modéliser proprement les circonstances de la vie réelle, mais dans 90% des cas, l'héritage unique couvre probablement les besoins. Et l'héritage unique est simple et ne coûte rien.
De plus, je ne me soucie pas de la sécurité des types. Je pense que vous ne devriez pas dépendre du compilateur pour vous éviter des erreurs de programmation. Et cela ne vous protège de toute façon que d'une petite partie des erreurs.
En règle générale, dans un environnement orienté objet, vous souhaitez également implémenter le comptage des références pour automatiser autant que possible la gestion de la mémoire. J'ai donc également mis un décompte de références dans la classe racine «Object» et quelques fonctionnalités pour encapsuler l'allocation et la désallocation de la mémoire du tas.
Tout cela est très simple et léger et me donne l'essentiel d'OO sans me forcer à faire face au monstre qu'est le C ++. Et je conserve la flexibilité de rester en C land, ce qui facilite entre autres l'intégration de bibliothèques tierces.
la source
Je propose d'utiliser Objective-C, qui est un surensemble de C.
Si Objective-C a 30 ans, il permet d'écrire du code élégant.
http://en.wikipedia.org/wiki/Objective-C
la source
Oui, mais je n'ai jamais vu personne tenter d'implémenter un quelconque polymorphisme avec C.
la source