Pour simuler la programmation à objets en C, une deuxième solution consiste à faire de surface, non une fonction, mais un champ fonctionnel intégré dans la définition d'un type Objet et à faire en sorte que les objets des sous-classes Point, Cercle et Rectangle contiennent un Objet, sous forme d'un champ super :
typedef struct Objet{
double (*surface)(struct Objet *);
} Objet;
typedef struct {
Objet super;
double x,y;
} Point;
typedef struct{
Objet super;
Point *centre;
double rayon;
} Cercle;
Pour chaque classe d'objet, on définit ensuite une fonction de calcul de la surface, toutes ces fonctions prenant un argument de type Objet :
double surfaceCercle(Objet *o) {
double r = ((Cercle *)o)->rayon;
return PI * r * r;
}
Ces fonctions surfacePoint, surfaceCercle et surfaceRectangle ne sont pas destinées à être appelées directement, mais seulement à être affectées, dans chaque constructeur, au champ fonctionnel surface de super, de sorte que l'objet << sait >> quelle méthode de calcul de la surface doit lui être appliquée :
Cercle *newCercle(Point *p, double r) {
Cercle *c = malloc(sizeof(Cercle));
((Objet *)c)->surface = surfaceCercle;
c->centre = p;
c->rayon = r;
return c;
}
L'utilisation d'un Cercle en tant qu'Objet se fait par une coercition (Objet *), comme dans la solution présentée au § 108 ; c'est maintenant le champ fonctionnel surface qui est appelé :
Objet
*c = (Objet *)newCercle(newPoint(0,0), 1);
double sc = (c->surface)(c);
Ceci fonctionne également grâce à la propriété d'allocation ordonnée des champs des structures. Ainsi, le premier champ de Cercle est aussi le premier champ d'Objet, et c'est l'adresse de la fonction surface.
Cette solution illustre quelques caractéristiques du style à objet. D'abord, chacun des types Point, Cercle et Rectangle étend le type Objet par l'addition de nouveaux champs : c'est la notion d'extension des classes, ou de sous-classage . Dans le cas présent, ceci permet de considérer Cercle comme un sous-type d'Objet, au sens où toute opération sur le type Objet peut être faite aussi sur le type Cercle, de la même façon que int peut être considéré comme un sous-type de double.
Les méthodes sont intégrées à la définition des classes, au lieu d'être des fonctions indépendantes, ce qui assure une certaine modularité. La méthode surface de la classe Objet est virtuelle , au sens où ce champ fonctionnel ne reçoit de valeur que dans les sous-classes d'Objet. Enfin, l'invocation de cette méthode se fait par une liaison tardive , au sens où la détermination de la fonction (surfacePoint, ...) qui sera effectivement invoquée ne peut être faite qu'à l'exécution.
Il ne s'agit que d'une simulation en C, approximative, maladroite voire dangereuse, de certaines caractéristiques du style à objets. Le recours aux langages à objets permet de bénéficier de façon beaucoup plus simple et sûre de ces diverses caractéristiques. Leur utilisation judicieuse, requise pour le développement de systèmes logiciels complexes, reste cependant assez difficile - et une affaire de goût.