• [^] # Re: Sans pointeurs de fonction

    Posté par . En réponse au journal C(++) ?. Évalué à 2.

    Francesco a écrit:

    En quoi est-ce redondant ? En C++, le langage le fait pour nous, et c'est le pointeur this. En C, il faut le faire manuellement.

    Je veux dire par là que la référence vers la structure est utilisée deux fois : d'abord pour obtenir le champ souhaité, ensuite comme argument de la fonction appelée. En bref, cela donne par exemple ceci :

    s.open(&s, "www.linuxfr.org",443);

    s est utilisé deux fois.

    Francesco a écrit:

    Tout dépend de comment est fait la structure. Si dans la structure, tu copies tous les pointeurs de fonction, alors oui, il y a gaspillage de mémoire. Maintenant, si dans la structure, tu mets un pointeur vers une autre structure contenant l'ensemble des pointeurs de fonction, alors non, il n'y a pas de perte de place, car il y aura alors une seule structure de pointeurs par "classe" et chaque occurrence de la classe pointera sur cette structure.

    En effet, c'est une solution envisageable, mais le code sera nettement moins lisible.

    s.method->open(&s, "www.linuxfr.org",443);
    

    Francesco a écrit:

    L'intérêt ? Le polymorphisme. Chose que tu ne pourras pas avoir en appelant directement la fonction, puisque la "résolution" de la fonction se fait à la compilation et que le polymorphisme impose une résolution dynamique (i.e., durant l'exécution).

    Il est tout à fait possible d'utiliser le polymorphisme en C sans utiliser massivement les pointeurs de fonctions. En fait, ils ne sont nécessaire que pour les fonctions virtuelles. Pour reprendre ton exemple, en C, cela donne :

    #include <stdio.h>
    #include <stdlib.h>
    struct forme_geometrique {
     struct forme_geometrique_vtable *vtable;
    };
    struct forme_geometrique_vtable {
     float (*area)(void *);
    };
    struct carre {
     struct carre_vtable *vtable;
     float len;
    };
    struct carre_vtable {
     struct forme_geometrique_vtable super;
    };
    struct circle {
     struct circle_vtable *vtable;
     float radius;
    };
    struct circle_vtable {
     struct forme_geometrique_vtable super;
    };
    extern struct carre *carre_create(float);
    extern void carre_destroy(struct carre *);
    extern float carre_area(void *);
    extern struct circle *circle_create(float);
    extern void circle_destroy(struct circle *);
    extern float circle_area(void *);
    extern float forme_geometrique_area(void *);
    struct carre *
    carre_create(float len)
    {
     static struct carre_vtable vtable = { { &carre_area } };
     struct carre *self;
     self = malloc(sizeof *self);
     if (self == NULL) {
     return NULL;
     }
     self->vtable = &vtable;
     self->len = len;
     return self;
    }
    void
    carre_destroy(struct carre *self)
    {
     if (self != NULL) {
     free(self);
     }
    }
    float
    carre_area(void *p)
    {
     struct carre *self;
     self = p;
     return self->len * self->len;
    }
    struct circle *
    circle_create(float radius)
    {
     static struct circle_vtable vtable = { { &circle_area } };
     struct circle *self;
     self = malloc(sizeof *self);
     if (self == NULL) {
     return NULL;
     }
     self->vtable = &vtable;
     self->radius = radius;
     return self;
    }
    void
    circle_destroy(struct circle *self)
    {
     if (self != NULL) {
     free(self);
     }
    }
    float
    circle_area(void *p)
    {
     struct circle *self;
     float const pi = 3.14F;
     self = p;
     return self->radius * self->radius * pi;
    }
    float
    forme_geometrique_area(void *p)
    {
     struct forme_geometrique *self;
     self = p;
     return self->vtable->area(p);
    }
    int
    main(void)
    {
     struct carre *carre;
     struct circle *circle;
     carre = carre_create(4);
     circle = circle_create(3.5);
     if (carre == NULL || circle == NULL) {
     return EXIT_FAILURE;
     }
     printf("%f\n", forme_geometrique_area(carre));
     printf("%f\n", forme_geometrique_area(circle));
     carre_destroy(carre);
     circle_destroy(circle);
     return 0;
    }