Pouvez-vous écrire du code orienté objet en C? Surtout en ce qui concerne le polymorphisme.
Voir aussi: http://stackoverflow.com/questions/415452/object-orientation-in-c
Pouvez-vous écrire du code orienté objet en C? Surtout en ce qui concerne le polymorphisme.
Voir aussi: http://stackoverflow.com/questions/415452/object-orientation-in-c
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.
Puisque vous parlez de polymorphisme alors oui, vous pouvez, nous faisions ce genre de trucs années avant le C++.
Fondamentalement, vous utilisez un struct
pour tenir à la fois les données et une liste de pointeurs de fonction à point pour les fonctions pertinentes pour ce type de données.
Ainsi, dans une communication de la classe, vous pourriez ouvrir, lire, écrire et près d'appel qui serait maintenue que quatre pointeurs de fonction dans la structure, à côté des données d'un objet, quelque chose comme:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And data goes here.
} tCommClass;
tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;
tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;
Bien sûr, ces segments de code ci-dessus pourrait être en fait un "constructeur" comme rs232Init()
.
Lorsque vous 'inherit' à partir de cette classe, il suffit de changer les pointeurs au point de vos propres fonctions. Tout le monde qui a appelé à ces fonctions, serait-il le faire à travers les pointeurs de fonction, vous donnant votre polymorphisme:
int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");
Comme une sorte de manuel de la vtable.
Vous pourriez même avoir des classes virtuelles, en définissant les pointeurs à NULL le comportement serait légèrement différent du C++ (un core dump au moment de l'exécution plutôt que d'une erreur au moment de la compilation).
Voici un exemple de code qui illustre cela. D'abord le niveau supérieur de la structure de classe:
#include <stdio.h>
// The top-level class.
typedef struct _tCommClass {
int (*open)(struct _tCommClass *self, char *fspec);
} tCommClass;
Ensuite, nous avons les fonctions pour le TCP 'sous-classe':
// Function for the TCP 'class'.
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
Et la HTTP ainsi:
// Function for the HTTP 'class'.
static int httpOpen (tCommClass *http, char *fspec) {
printf ("Opening HTTP: %s\n", fspec);
return 0;
}
static int httpInit (tCommClass *http) {
http->open = &httpOpen;
return 0;
}
Et enfin un programme de test pour le montrer en action:
// Test program.
int main (void) {
int status;
tCommClass commTcp, commHttp;
// Same 'base' class but initialised to different sub-classes.
tcpInit (&commTcp);
httpInit (&commHttp);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHttp.open)(&commHttp, "http://www.microsoft.com");
return 0;
}
Ce produit de la sortie:
Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com
donc vous pouvez voir que les différentes fonctions sont appelés, selon la sous-classe.
Les espaces de noms sont souvent fait par:
stack_push(thing *)
au lieu de
stack::push(thing *)
Pour faire un c struct dans quelque chose comme une classe c++, vous pouvez vous tourner:
class stack {
public:
stack();
void push(thing *);
thing * pop();
static int this_is_here_as_an_example_only;
private:
...
};
En
struct stack {
struct stack_type * my_type;
// put the stuff that you put after private: here
};
struct stack_type {
void (* construct)(struct stack * this); // this takes uninitialized memory
struct stack * (* operator_new)(); // this allocates a new struct, passes it to construct, and then returns it
void (*push)(struct stack * this, thing * t); // pushing t onto this stack
thing * (*pop)(struct stack * this); // pops the top thing off the stack and returns it
int this_is_here_as_an_example_only;
}Stack = {
.construct = stack_construct,
.operator_new = stack_operator_new,
.push = stack_push,
.pop = stack_pop
};
// all of these functions are assumed to be defined somewhere else
et faire:
struct stack * st = Stack.operator_new(); // make a new stack
if (!st) {
// do something about it
} else {
// you can use the stack
stack_push(st, thing0); // This is a non-virtual call
Stack.push(st, thing1); // This is like casting *st to a Stack (which it already is) and doing the push
st->my_type.push(st, thing2); // This is a virtual call
}
Je n'ai pas fait le destructeur ou supprimer, mais il suit le même schéma.
this_is_here_as_an_example_only est comme une classe statique variable -- partagée entre toutes les instances d'un type. Toutes les méthodes sont vraiment statique, sauf que certains de prendre un ce *
Je crois qu'en plus d'être utile dans son propre droit, la mise en œuvre de la programmation orientée objet en C est un excellent moyen pour apprendre la programmation orientée objet et de comprendre son fonctionnement interne. L'expérience de beaucoup de programmeurs a montré que l'utilisation d'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 de classes, l'héritage et le polymorphisme en C enseigne tout cela.
Pour répondre à la question d'origine, voici quelques ressources qui nous enseignent comment faire de la POO en C:
EmbeddedGurus.com blog post "Objet de base de la programmation en C", montre comment mettre en œuvre les classes et l'héritage simple en C portable: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c/
Note d'Application ""C+"-Programmation Orientée Objet en C", montre comment mettre en œuvre les classes, l'héritage simple, et la liaison tardive (polymorphisme) en C à l'aide de macros du préprocesseur: http://www.state-machine.com/resources/cplus_3.0_manual.pdfl'exemple de code est disponible à partir de http://www.state-machine.com/resources/cplus_3.0.zip
Je l'ai vu faire. Je ne le recommande pas. C++ à l'origine commencé comme un préprocesseur qui produit du code C comme une étape intermédiaire.
Essentiellement, ce que vous faire est de créer un tableau de répartition pour l'ensemble de vos méthodes dans lesquelles vous pouvez stocker vos références de fonction. La dérivation d'une classe serait une copie d'envoi de ce tableau et de remplacer les entrées que vous vouliez remplacer, avec vos nouvelles "méthodes" d'avoir à appeler la méthode originale si elle veut invoquer la méthode de base. Finalement, vous réécrire en C++.
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.