6 novembre 2021
Ce texte fait partie d’une petite collection de notes mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 2.0 France.
Dernières corrections : 6 novembre.
Dans cette note on montre comment réaliser une sorte de polymorphisme en C, à savoir la possibilité d’appliquer la même fonction à des objets de types différents, avec un comportement spécifique pour chaque type d’objet.
On aura une séparation entre interface (au sens Java) et les types concrets qui implémenteront cette interface.
L’interface recense les fonctions applicables indifféremment aux types qui l’implémentent (“fonctions virtuelles”). Ici on aura une interface Animal
avec deux fonctions Animal_Talk()
et Animal_Feed()
.
typedef void (*ANIMAL_TALK_METHOD)(void *);
typedef void (*ANIMAL_FEED_METHOD)(void *, char *);
typedef struct {
ANIMAL_TALK_METHOD talk;
ANIMAL_FEED_METHOD feed; } AnimalVtable;
typedef struct {
// table de pointeurs de fonctions
AnimalVtable *vtable; } Animal;
Animal
:void Animal_Talk(void *this)
{
Animal *animal = this;
animal->vtable->talk(this);
}
void Animal_Feed(Animal *this, char *food)
{
Animal *animal = this;
animal->vtable->feed(this, food); }
Dog
Dog
, possède un attribut spécifique (name
) :typedef struct {
AnimalVtable *vtable;char * name; // attribut
} Dog;
talk()
et feed()
void Dog_Talk(void *this) // fonction talk
{
Dog *dog = this;"%s> Wah!\n", dog->name);
printf(
}
void Dog_Feed(void *this, char * what) // fonction feed
{
Dog *dog = this;void) dog;
("thanks for %s !\n", what);
printf(
}
// vtable pour Dog
AnimalVtable DogVtable = {
.talk = & Dog_Talk,
.feed = & Dog_Feed };
new_Dog
est chargée d’allouer une nouvelle instance, et initialise sa vtable et ses champs :char *name)
Dog *new_Dog(
{sizeof(Dog));
Dog * p = malloc(
p->vtable = & DogVtable;
p->name = name;return p;
}
main()
Animal_Talk
et Animal_Feed
, pour montrer les comportement spécifiquesint main()
{
Animal * animals[] = {"Medor"),
(Animal *) new_Dog("Yellow"),
(Animal *) new_Fish("Rex")
(Animal *) new_Dog(
};
for (int i = 0; i < 3; i++) {
Animal_Talk(animals[i]);"the kibbles"); // croquettes
Animal_Feed(animals[i],
}
for (int i = 0; i < 3; i++) {
free(animals[i]);
} }
#include <stdio.h>
#include <stdlib.h>
// tout objet polymorphe a une table de fonctions
// comme premier membre
typedef void (*ANIMAL_TALK_METHOD)(void *);
typedef void (*ANIMAL_FEED_METHOD)(void *, char *);
typedef struct {
ANIMAL_TALK_METHOD talk;
ANIMAL_FEED_METHOD feed;
} AnimalVtable;
typedef struct {
// table de pointeurs de fonctions
AnimalVtable *vtable;
} Animal;
void Animal_Talk(void *this)
{
Animal *animal = this;
animal->vtable->talk(this);
}
void Animal_Feed(Animal *this, char *food)
{
Animal *animal = this;
animal->vtable->feed(this, food);
}
// -------------------------------------------
typedef struct {
AnimalVtable *vtable;// les attributs vont ici
char * name;
} Dog;
void Dog_Talk(void *this)
{
Dog *dog = this;"%s> Wah!\n", dog->name);
printf(
}
void Dog_Feed(void *this, char * what)
{
Dog *dog = this;void) dog;
("thanks for %s !\n", what);
printf(
}
AnimalVtable DogVtable = {
.talk = & Dog_Talk,
.feed = & Dog_Feed
};
char *name)
Dog *new_Dog(
{sizeof(Dog));
Dog * p = malloc(
p->vtable = & DogVtable;
p->name = name;return p;
}
// ---------------------------------------------
typedef struct {
AnimalVtable *vtable;char *color;
} Fish;
void Fish_Talk(void *this)
{
Fish *fish = this;"%s fish -> Bloup!\n", fish->color);
printf(
}
void Fish_Feed(void *this, char * what)
{
Fish *fish = this;void) fish;
(void) what;
("No thanks\n");
printf(
}
AnimalVtable fishVtable = {
.talk = & Fish_Talk,
.feed = & Fish_Feed
};
char *color)
Fish *new_Fish(
{sizeof(Fish));
Fish * p = malloc(
p->vtable = & fishVtable;
p->color = color;return p;
}
int main()
{
Animal * animals[] = {"Medor"),
(Animal *) new_Dog("Yellow"),
(Animal *) new_Fish("Rex")
(Animal *) new_Dog(
};
for (int i = 0; i < 3; i++) {
Animal_Talk(animals[i]);"the kibbles"); // croquettes
Animal_Feed(animals[i],
}
for (int i = 0; i < 3; i++) {
free(animals[i]);
} }
La compilation ne nécessite pas d’option spécifique. Le code est conforme au standard c17.
gcc -Wall -Wextra -pedantic -std=c17 demo.c -o demo
Exécution
./demo
Medor> Wah!
thanks for the kibbles !
Yellow fish -> Bloup!
No thanks
Rex> Wah!
thanks for the kibbles !