55 votes

Programmation orientée objet en C

Possible Duplicates:
Peut-on écrire du code orienté objet en C ?
Patron orienté objet en C ?

I remember reading il y a quelque temps à propos de quelqu'un (je pense que c'était Linus Torvalds) parlant de la mauvaise langue que C++ est et de comment vous pouvez écrire des programmes orientés objet en C. Après avoir eu le temps de réfléchir, je ne vois pas vraiment comment tous les concepts orientés objet peuvent être utilisés en C. Certaines choses sont assez évidentes. Par exemple:

  1. Pour émuler les fonctions membres, vous pouvez mettre des pointeurs de fonction dans des structures.
  2. Pour émuler la polymorphie, vous pouvez écrire une fonction qui prend un nombre variable d'arguments et faire des tours de magie en fonction, disons, de la sizeof du ou des paramètre(s)

Comment émuler l'encapsulation et l'héritage cependant ?

Je suppose que l'encapsulation pourrait être émulée en ayant une structure imbriquée qui stocke des membres privés. Il serait assez facile de contourner, mais pourrait peut-être être nommée PRIVATE ou quelque chose d'aussi évident pour signaler que ce n'est pas censé être utilisé en dehors de la structure. Et l'héritage alors ?

4 votes

C'est assez pénible à mon avis. C'est pourquoi nous avons des langages de haut niveau.

0 votes

Utilisation sérieuse de stackoverflow pour la construction de profil en ligne. Pourquoi diable quelqu'un voudrait-il faire cela??.

76voto

Tronic Points 6457

Vous pouvez implémenter le polymorphisme avec des fonctions régulières et des tables virtuelles (vtables). Voici un système plutôt ingénieux que j'ai inventé (basé sur C++) pour un exercice de programmation : texte alternatif

Les constructeurs allouent de la mémoire puis appellent la fonction d'initialisation de la classe où la mémoire est initialisée. Chaque fonction d'initialisation doit également contenir une structure vtable statique qui contient les pointeurs de fonction virtuelle (NULL pour les fonctions virtuelles pures). Les fonctions d'initialisation des classes dérivées appellent la fonction d'initialisation de la super classe avant de faire quoi que ce soit d'autre.

Une API très pratique peut être créée en implémentant les wrappers de fonctions virtuelles (à ne pas confondre avec les fonctions pointées par les vtables) comme suit (ajoutez static inline devant, si vous le faites dans l'en-tête) :

int playerGuess(Joueur* this) { return this->vtable->guess(this); }

L'héritage simple peut être réalisé en abusant de la mise en page binaire d'une structure : texte alternatif

Remarquez que l'héritage multiple est plus compliqué car vous devez souvent ajuster la valeur du pointeur lors de la conversion entre les types de la hiérarchie.

D'autres données spécifiques au type peuvent également être ajoutées aux tables virtuelles. Des exemples incluent des informations de type en temps d'exécution (par exemple, le nom du type en tant que chaîne), le lien vers la vtable de la super classe et la chaîne de destructeurs. Vous voudrez probablement des destructeurs virtuels où le destructeur de la classe dérivée rétrograde l'objet vers sa super classe puis appelle récursivement le destructeur de cette dernière, et ainsi de suite, jusqu'à ce que le destructeur de la classe de base soit atteint et que la structure soit enfin libérée.

L'encapsulation a été réalisée en définissant les structures dans player_protected.h et en implémentant les fonctions (pointées par la vtable) dans player_protected.c, et de manière similaire pour les classes dérivées, mais c'est assez maladroit et cela dégrade les performances (car les wrappers virtuels ne peuvent pas être placés dans les en-têtes), donc je le déconseillerais.

7 votes

+1 pour les jolies images.

0 votes

@Tronic - Je ne suis pas sûr que vous soyez un expert en Java, mais la façon dont le HotSpot JVM implémente l'OO est très similaire à cela. Bien sûr, Java n'autorise qu'une seule implémentation pour l'héritage, ce qui résout le casse-tête de l'héritage multiple. Il se peut que je doive rediriger les personnes habituées au C/C++ ici si je dois leur expliquer Java / JVM OO à l'avenir.

4 votes

C++ implémente également la POO de cette manière.

29voto

Kornel Kisielewicz Points 26556

Avez-vous lu la "bible" sur le sujet? Voir Object Oriented C...

0 votes

@tur1ng - par accident - J'ai l'extension PDF installée dans Chrome :>

0 votes

Merci pour le post. Quel est le nom du prochain et de l'auteur ? Il n'est pas répertorié dans le fichier.

8voto

John Knoeller Points 20754

Comment émuleriez-vous l'encapsulation et l'héritage cependant ?

En fait, l'encapsulation est la partie la plus facile. L'encapsulation est une philosophie de conception, elle n'a rien à voir du tout avec le langage et tout à voir avec la façon dont vous pensez aux problèmes.

Par exemple, l'API de fichier Windows est complètement encapsulée. Lorsque vous ouvrez un fichier, vous récupérez un objet opaque qui contient toutes les informations d'état pour l'objet de fichier. Vous redonnez cette poignée à chacune des API d'entrée/sortie de fichier. L'encapsulation est en fait beaucoup meilleure que C++ car il n'y a aucun fichier d'en-tête public que les gens peuvent consulter et voir les noms de vos variables privées.

L'héritage est plus difficile, mais il n'est pas du tout nécessaire pour que votre code soit orienté objet. À bien des égards, l'agrégation est meilleure que l'héritage de toute façon, et l'agrégation est aussi simple en C qu'en C++. voir ceci par exemple.

En réponse à Neil voir Wikipedia pour une explication de pourquoi l'héritage n'est pas nécessaire pour le polymorphisme.

Nous, les anciens, avons écrit du code orienté objet des années avant que les compilateurs C++ soient disponibles, c'est une manière de penser et non un ensemble d'outils.

1 votes

Si vous n'avez pas l'héritage, vous n'avez pas de polymorphisme à l'exécution, et vous n'avez pas de POO.

2 votes

@Neil: Je ne te vois pas faire souvent des erreurs, mais ici tu as complètement tort. L'héritage n'est pas une fonctionnalité nécessaire de la POO. Tu peux obtenir le polymorphisme grâce à l'agrégation / délégation.

0 votes

Vous ne considéreriez pas Ada83 comme orienté objet, pourtant il possède toutes les fonctionnalités à l'exception de l'héritage et du polymorphisme. Je suis d'accord avec Neil. Dire le contraire reviendrait à abandonner complètement le but pour lequel le paradigme POO a été inventé : la réutilisation du code.

5voto

Chuck Points 138930

Le framework CoreFoundation basé sur C d'Apple a en réalité été écrit de sorte que ses "objets" puissent également servir d'objets en Objective-C, un langage orienté objet réel. Une assez grande partie du framework est open source sur le site d'Apple sous le nom de CF-Lite. Cela pourrait être une étude de cas utile pour un framework de niveau OS majeur réalisé de cette manière.

5voto

mloskot Points 13971

À partir d'une altitude un peu plus élevée et en considérant le problème de manière plus ouverte que ne le suggère généralement le courant principal de la POO, la Programmation Orientée Objet signifie penser aux objets comme des données avec des fonctions associées. Cela ne signifie pas nécessairement qu'une fonction doit être physiquement attachée à un objet comme c'est le cas dans les langages populaires qui supportent le paradigme de la POO, par exemple en C++:

struct T
{
   int data;
   int get_data() const { return data; }
};

Je suggère de jeter un coup d'œil plus attentif au Système d'Objets et de Types GTK+. C'est un brillant exemple de POO réalisé en langage C :

GTK+ implémente son propre système d'objet personnalisé, qui offre des fonctionnalités orientées objet standard telles que l'héritage et les fonctions virtuelles

L'association peut aussi être contractuelle et conventionnelle.

En ce qui concerne les techniques d'encapsulation et de masquage des données, une technique populaire et simple pourrait être le Pointeur Opaque (ou Type de Données Opaque) - vous pouvez le transmettre mais pour charger ou stocker des informations, vous devez appeler la fonction associée qui sait comment communiquer avec l'objet caché derrière ce pointeur opaque.

Une autre technique, similaire mais différente, est le Type de Données Shadow - consultez ce lien où Jon Jagger donne une excellente explication de cette technique peu connue.

0 votes

Donc comment implémenter des interfaces sans réellement attacher des méthodes à l'objet ? Je pense que votre pointeur opaque pourrait répondre à cela, mais je ne comprends pas comment sans exemple. Le langage de programmation Go partage votre philosophie très générique sur la POO mais ils ont quand même été obligés de permettre aux méthodes d'être attachées aux types afin de faciliter les interfaces.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X