2009-08-06 4 views
34

Est-il possible de modéliser l'héritage en utilisant C? Comment? Exemple de code va aider.Comment Hériter peut-il être modélisé avec C?

Modifier: Je cherche à hériter des données et des méthodes. Le conteneur à lui seul n'aidera pas. La substituabilité - utiliser n'importe quel objet de classe dérivé où travaille un objet de classe de base - est ce dont j'ai besoin.

+0

Quelle est la raison de le faire? –

+0

J'ai du code C en utilisant principalement des porte-conteneurs. Le projet est arrivé à un point où la substituabilité (une relation «est un») est devenue très souhaitable. –

+0

répond essentiellement à toutes vos questions: [http://stackoverflow.com/questions/415452/object-orientation-in-c/415536#415536](http://stackoverflow.com/questions/415452/object-orientation-in -c/415536 ​​# 415536) – Junier

Répondre

3

Cela devrait être possible, au moins dans une certaine mesure.

De quoi avez-vous besoin exactement pour modéliser? L'héritage des données ou des méthodes?

Modifier: Voici un court article que j'ai trouvé: http://fluff.info/blog/arch/00000162.htm

1

Ce lien peut être utile ->link

exemple de base sera comme suivre

struct BaseStruct 
{ 
    // some variable 
} 


struct DerivedStruct 
{ 
    struct BaseStruct lw; 
    // some more variable 
}; 
2

Depuis les premières versions de C++ était principalement un préprocesseur converti en C, c'est deiniment possible.

20

Il est très simple à se présenter comme suit:

struct parent { 
    int foo; 
    char *bar; 
}; 

struct child { 
    struct parent base; 
    int bar; 
}; 

struct child derived; 

derived.bar = 1; 
derived.base.foo = 2; 

Mais si vous utilisez l'extension MS (dans GCC utiliser -fms-extensions drapeau), vous pouvez utiliser struct imbriqués anonymes s et il sera beaucoup mieux:

struct child { 
    struct parent; // anonymous nested struct 
    int bar; 
}; 

struct child derived; 

derived.bar = 1; 
derived.foo = 2;  // now it is flat 
+0

bien, mais maintenant CLang ne compilera pas cela .. – makapuf

+0

@makapuf C11 le prend en charge en tant que fonctionnalité standard (https://en.wikipedia.org/wiki/C11_(C_standard_revision)#Changes_from_C99), donc 'clang' devrait prendre en charge avec -std = c11' – qrdl

+0

bien, pas exactement, il semble. C11 l'accepte avec des structures anonymes non étiquetées, donc vous pouvez intégrer une autre structure non nommée mais ne peut pas réutiliser une définition de structure précédente ... (pourquoi c'est le cas je ne sais pas). – makapuf

2

J'ai utilisé un système d'objets en C qui utilisait des méthodes à liaison tardive, ce qui permettait une orientation d'objet avec réflexion.

Vous pouvez lire à ce sujet here.

+0

en effet; le sujet est beaucoup trop large pour couvrir entièrement dans une seule réponse sur stackoverflow. A première vue, je pense que l'article lié à couvre une bonne affaire. J'aime l'explication de Miro Samek dans "Practical Statecharts in C/C++" (1ère édition seulement) – Adriaan

8

Vous pouvez certainement écrire C dans un style (un peu) orienté objet.

L'encapsulation peut être effectuée en conservant les définitions de vos structures dans le fichier .c plutôt que dans l'en-tête associé. Puis le monde extérieur gère vos objets en gardant des pointeurs sur eux, et vous fournir des fonctions acceptant des pointeurs tels que les "méthodes" de vos objets.

comportement Polymorphisme semblable peut être obtenu en utilisant des pointeurs de fonctions, généralement regroupées au sein de « structures d'exploitation », un peu comme la « table de méthode virtuelle » dans votre C++ objets (ou quelque chose comme ça). La structure ops peut également inclure d'autres éléments tels que constantes dont la valeur est spécifique à une "sous-classe" donnée. La structure "parent" peut conserver une référence à des données spécifiques à l'op via un pointeur générique void*. Bien sûr, la "sous-classe" pourrait répéter le modèle pour plusieurs niveaux de l'héritage.

Ainsi, dans l'exemple ci-dessous, struct printer est semblable à une classe abstraite, qui peut être « dérivée » en complétant une structure pr_ops, et fournir une fonction de constructeur d'emballage pr_create(). Chaque sous-type aura sa propre structure qui sera "ancrée" à l'objet struct printer via le pointeur générique data. Ceci est démontré par le sous-type fileprinter. On pourrait imaginer une imprimante GUI ou socket, qui serait manipulée indépendamment du reste du code comme référence struct printer *.

printer.h:

struct pr_ops { 
    void (*printline)(void *data, const char *line); 
    void (*cleanup)(void *data); 
}; 

struct printer *pr_create(const char *name, const struct output_ops *ops, void *data); 
void pr_printline(struct printer *pr, const char *line); 
void pr_delete(struct printer *pr); 

printer.c:

#include "printer.h" 
... 

struct printer { 
    char *name; 
    struct pr_ops *ops; 
    void *data; 
} 

/* constructor */ 
struct printer *pr_create(const char *name, const struct output_ops *ops, void *data) 
{ 
    struct printer *p = malloc(sizeof *p); 
    p->name = strdup(name); 
    p->ops = ops; 
    p->data = data; 
} 

void pr_printline(struct printer *p, const char *line) 
{ 
    char *l = malloc(strlen(line) + strlen(p->name) + 3; 
    sprintf(l, "%s: %s", p->name, line); 
    p->ops->printline(p->data, l); 
} 

void pr_delete(struct printer *p) 
{ 
    p->ops->cleanup(p->data); 
    free(p); 
} 

Enfin, fileprinter.c:

struct fileprinter { 
    FILE *f; 
    int doflush; 
}; 

static void filepr_printline(void *data, const char *line) 
{ 
    struct fileprinter *fp = data; 
    fprintf(fp->f, "%s\n", line); 
    if(fp->doflush) fflush(fp->f); 
} 

struct printer *filepr_create(const char *name, FILE *f, int doflush) 
{ 
    static const struct ops = { 
     filepr_printline, 
     free, 
    }; 

    struct *fp = malloc(sizeof *fp); 
    fp->f = f; 
    fp->doflush = doflush; 
    return pr_create(name, &ops, fp); 
} 
+8

+1. Aussi comme note historique - les premiers compilateurs C++ n'ont pas sorti le code machine mais le code C parce qu'il était plus rapide et plus facile à implémenter (la couche de code C à machine existante). Donc, ça peut gdefinitely peut être fait en C. – TomTom

1
#include <stdio.h> 

///////Class Cobj 
typedef struct Cobj{ 
    int x; 
    void (*setptr)(char * s,int val); 
    int (*getptr)(char * s); 
} Cobj; 

void set(char * s,int val) 
{ 
    Cobj * y=(Cobj *)s; 
    y->x=val; 
} 
int get(char * s){ 
    Cobj * y=(Cobj *)s; 
    return y->x; 
} 
///////Class Cobj 
Cobj s={12,set,get}; 
Cobj x; 

void main(void){ 
    x=s; 
    x.setptr((char*)&x,5); 
    s.setptr((char*)&s,8); 
    printf("%d %d %d",x.getptr((char*)&x),s.getptr((char*)&s) ,sizeof(Cobj)); 
} 
1

Oui, vous pouvez émuler Heritance en C en utilisant la technique "type punting". C'est la déclaration de la classe de base (struct) dans la classe dérivée, et CAST la dérivée comme base:

struct base_class { 
    int x; 
}; 

struct derived_class { 
    struct base_class base; 
    int y; 
} 

struct derived_class2 { 
    struct base_class base; 
    int z; 
} 
void test() { 
    struct derived_class d; 
    struct derived_class2 d2; 

    d.base.x = 10; 
    d.y = 20; 

    printf("x=%i, y=%i\n", d.base.x, d.y); 
} 

Mais vous devez déclarer la classe de base dans la première position en vous structure dérivée, si vous voulez convertir le dérivé en tant que base dans un programme:

struct base *b1, *b2; 

b1 = (struct base *)d; 
b2 = (struct base *)d2; 

b1->x=10; 
b2->x=20; 
printf("b1 x=%i, b2 x=%i\n", b1->x, b2->x); 

Dans cet extrait, vous pouvez uniquement utiliser la classe de base.

J'utilise cette technique dans mes projets: oop4c

+0

Ne devrait-il pas être & d et & d2? –

Questions connexes