dimanche 25 janvier 2009
Une base de données orientée objet : Db4o
J’ai eu l’occasion d’essayer Db4o une base de données orientées objet libre, la facilité d’utilisation de cet outil est assez troublante. En l’utilisant on se demande vraiment pourquoi autant de gens s’embêtent avec des ORMs. Toutefois la prudence est de mise, si je pense que cette solution est adapté pour des petits projets, je n’ai pas pu faire de tests de performances avec cette base de données, je n’ai pas non plus essayé de persister des objets complexes. Le gain en productivité avec cette base de données est plus important selon moi qu’avec un ORM comme hibernate. Je trouve que ce type de base gagnerait à être connu dans la mesure où elles tentent de répondre à la demande actuelle, à savoir persister facilement et si possible rapidement des objets. J’ai décelé quelques points noirs, tout d’abord la documentation, le « Formula One Tutorial » bien qu’amusant à faire il est un peu négligé, d’une part il propose d’utiliser des méthodes dépréciés (problème de mise à jour de la documentation ?) d’autre part le « full source » est incomplet. Autre point noir, la licence, cette sympathique base de données est sous licence GPL, donc tout logiciel utilisant cette base de données bascule sous licence GPL…. Néanmoins ce type de base données trace une nouvelle voie : Plutôt que faire rentrer un model objet dans une base de données relationnelles ou un modèle relationnel dans un modèle objet à l’aide d’ORMs, autant utiliser une base de données capable de comprendre nativement un model objet.
Quelques bouts de codse pour montrer ce que l’on peut faire avec :
MyClass.java :
package com.db4o.f1.chapter1;
import java.io.File;
import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
public class MyClass {
public static void main(String[] args) {
new File("c:/database").delete();
accessDb4o();
new File("c:/database").delete();
ObjectContainer db = Db4o.openFile("c:/database");
try {
storeFirstPilot(db);
storeSecondPilot(db);
retrieveAllPilots(db);
retrievePilotByName(db);
retrievePilotByExactPoints(db);
updatePilot(db);
deleteFirstPilotByName(db);
deleteSecondPilotByName(db);
} finally {
db.close();
}
}
public static void accessDb4o() {
ObjectContainer db = Db4o.openFile("c:/database");
try {
// do something with db4o
} finally {
db.close();
}
}
public static void storeFirstPilot(ObjectContainer db) {
Pilot pilot1 = new Pilot("Michael Schumacher", 100);
db.set(pilot1);
System.out.println("Stored " + pilot1);
}
public static void storeSecondPilot(ObjectContainer db) {
Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
db.set(pilot2);
System.out.println("Stored " + pilot2);
}
public static void retrieveAllPilotQBE(ObjectContainer db) {
Pilot proto = new Pilot(null, 0);
ObjectSet result = db.get(proto);
listResult(result);
}
public static void listResult(ObjectSet result) {
System.out.println(result.size());
while (result.hasNext()) {
System.out.println(result.next());
}
}
public static void retrieveAllPilots(ObjectContainer db) {
ObjectSet result = db.get(Pilot.class);
listResult(result);
}
public static void retrievePilotByName(ObjectContainer db) {
Pilot proto = new Pilot("Michael Schumacher", 0);
ObjectSet result = db.get(proto);
listResult(result);
}
public static void retrievePilotByExactPoints(ObjectContainer db) {
Pilot proto = new Pilot(null, 100);
ObjectSet result = db.get(proto);
listResult(result);
}
public static void updatePilot(ObjectContainer db) {
ObjectSet result = db.get(new Pilot("Michael Schumacher", 0));
Pilot found = (Pilot) result.next();
found.addPoints(11);
db.set(found);
System.out.println("Added 11 points for " + found);
retrieveAllPilots(db);
}
public static void deleteFirstPilotByName(ObjectContainer db) {
ObjectSet result = db.get(new Pilot("Michael Schumacher", 0));
Pilot found = (Pilot) result.next();
db.delete(found);
System.out.println("Deleted " + found);
retrieveAllPilots(db);
}
public static void deleteSecondPilotByName(ObjectContainer db) {
ObjectSet result = db.get(new Pilot("Rubens Barrichello", 0));
Pilot found = (Pilot) result.next();
db.delete(found);
System.out.println("Deleted " + found);
retrieveAllPilots(db);
}
}
Pilot.java :
package com.db4o.f1.chapter1;
public class Pilot {
private String name;
private int points;
public Pilot(String name,int points) {
this.name=name;
this.points=points;
}
public int getPoints() {
return points;
}
public void addPoints(int points) {
this.points+=points;
}
public String getName() {
return name;
}
public String toString() {
return name+"/"+points;
}
}
Le C orienté objet, 3ème partie
Voici un troisième exemple de « classe » écrite en langage C, cette version de distingue de ses précédentes par la présence d’une certaine forme d’encapsulation. Les développeurs qui manipuleront une instance de la classe « ClasseEncapsule » n’auront pas un accès direct aux champs de cette instance, ils devront passer par des accesseurs et des mutateurs. On peut trouver ces derniers inutiles dans la mesure où la plupart du temps ils se contentent de faire de simples affectations, mais ils permettent de masquer l’implémentation et ainsi de minimiser l’impact des modifications de la classe « ClasseEncapsule ».
ClasseEncapsule.h :
#ifndef CLASSEENCAPSULE_H_INCLUDED
#define CLASSEENCAPSULE_H_INCLUDED
typedef struct ClasseEncapsule *ClasseEncapsule;
extern void ClasseEncapsule_supprimer(ClasseEncapsule
maClasse);
extern double
ClasseEncapsule_methode1(ClasseEncapsule maClasse,double unDouble);
extern char *
ClasseEncapsule_methode2(ClasseEncapsule maClasse,int unInt, char * unCharEtoile);
extern ClasseEncapsule
ClasseEncapsule_creer(int champ1, double champ2, char * champ3);
extern int ClasseEncapsule_acceder_champ1(ClasseEncapsule maClasse);
extern double ClasseEncapsule_acceder_champ2(ClasseEncapsule maClasse);
extern char * ClasseEncapsule_acceder_champ3(ClasseEncapsule maClasse);
extern void ClasseEncapsule_muter_champ1(ClasseEncapsule maClasse, int valeur);
extern void ClasseEncapsule_muter_champ2(ClasseEncapsule maClasse,double valeur);
extern void ClasseEncapsule_muter_champ3(ClasseEncapsule maClasse,char * valeur);
#define ClasseEncapsuleUpCast(instance,instanceSousClasse, NOM_CLASSE_FILLE) \
ClasseEncapsule_muter_champ1(instance,NOM_CLASSE_FILLE##_acceder_champ1(instanceSousClasse)); \
ClasseEncapsule_muter_champ2(instance,NOM_CLASSE_FILLE##_acceder_champ2(instanceSousClasse)); \
ClasseEncapsule_muter_champ3(instance,NOM_CLASSE_FILLE##_acceder_champ3(instanceSousClasse));
#define ClasseEncapsuleDownCast(instance,instanceSousClasse, NOM_CLASSE_FILLE) \
NOM_CLASSE_FILLE##_muter_champ1(instanceSousClasse,ClasseEncapsule_acceder_champ1(instance)); \
NOM_CLASSE_FILLE##_muter_champ2(instanceSousClasse,ClasseEncapsule_acceder_champ2(instance)); \
NOM_CLASSE_FILLE##_muter_champ3(instanceSousClasse,ClasseEncapsule_acceder_champ3(instance));
#endif // CLASSEENCAPSULE_H_INCLUDED
ClasseEncapsuleImpl.h :
#ifndef CLASSEENCAPSULEIMPL_H_INCLUDED
#define CLASSEENCAPSULEIMPL_H_INCLUDED
#define ClasseEncapsule_methode1_IMPL(instanceClasseMere, unDouble) \
return instanceClasseMere->monChamp2 + (unDouble);
#define ClasseEncapsule_methode2_IMPL( instanceClasseMere, unInt,unCharEtoile) \
if(strlen(unCharEtoile) > (unInt)){\
return unCharEtoile;\
}\
return instanceClasseMere->monChamp3;
#define ClasseEncapsule_supprimer_IMPL(instanceClasseMere) \
if(instanceClasseMere!=NULL){\
free(instanceClasseMere);\
}
#define ClasseEncapsule_acceder_champ1_IMPL(instanceClasseMere) \
return instanceClasseMere->monChamp1;
#define ClasseEncapsule_acceder_champ2_IMPL(instanceClasseMere) \
return instanceClasseMere->monChamp2;
#define ClasseEncapsule_acceder_champ3_IMPL(instanceClasseMere) \
return instanceClasseMere->monChamp3;
#define ClasseEncapsule_muter_champ1_IMPL(instanceClasseMere,valeur) \
instanceClasseMere->monChamp1=valeur;
#define ClasseEncapsule_muter_champ2_IMPL(instanceClasseMere,valeur) \
instanceClasseMere->monChamp2=valeur;
#define ClasseEncapsule_muter_champ3_IMPL(instanceClasseMere,valeur) \
instanceClasseMere->monChamp3=valeur;
#endif // CLASSEENCAPSULEIMPL_H_INCLUDED
ClasseEncapsule.c :
#include
#include
#include
#include "classeencapsule.h"
#include "classeencapsuleimpl.h"
struct ClasseEncapsule
{
int monChamp1;
double monChamp2;
char* monChamp3;
};
int ClasseEncapsule_acceder_champ1(ClasseEncapsule maClasse){
ClasseEncapsule_acceder_champ1_IMPL(maClasse);
}
double ClasseEncapsule_acceder_champ2(ClasseEncapsule maClasse){
ClasseEncapsule_acceder_champ2_IMPL(maClasse);
}
char * ClasseEncapsule_acceder_champ3(ClasseEncapsule maClasse){
ClasseEncapsule_acceder_champ3_IMPL(maClasse);
}
void ClasseEncapsule_muter_champ1(ClasseEncapsule maClasse, int valeur){
ClasseEncapsule_muter_champ1_IMPL(maClasse,valeur);
}
void ClasseEncapsule_muter_champ2(ClasseEncapsule maClasse,double valeur){
ClasseEncapsule_muter_champ2_IMPL(maClasse,valeur);
}
void ClasseEncapsule_muter_champ3(ClasseEncapsule maClasse,char * valeur){
ClasseEncapsule_muter_champ3_IMPL(maClasse,valeur);
}
void ClasseEncapsule_supprimer(ClasseEncapsule maClasse){
ClasseEncapsule_supprimer_IMPL(maClasse);
}
double
ClasseEncapsule_methode1(ClasseEncapsule maClasse,double unDouble){
ClasseEncapsule_methode1_IMPL(maClasse,unDouble);
}
char *
ClasseEncapsule_methode2(ClasseEncapsule maClasse,int unInt, char * unCharEtoile){
ClasseEncapsule_methode2_IMPL(maClasse,unInt,unCharEtoile);
}
ClasseEncapsule
ClasseEncapsule_creer(int champ1, double champ2, char * champ3)
{
ClasseEncapsule monInstance=malloc(sizeof(struct ClasseEncapsule));
monInstance->monChamp1=champ1;
monInstance->monChamp2=champ2;
monInstance->monChamp3=champ3;
return monInstance;
}
dimanche 14 décembre 2008
Le C orienté objet, 2ème partie
Lorsque nous avons une instance de la classe « ClasseFille » comment la passer en paramètre à une méthode qui prend en paramètre une instance de la classe « ClasseMere » ? Grace aux deux autres macros-fonctions « ClasseMereUpCast » et « ClasseMereDownCast » qui permettent respectivement le transtypage de la classe fille vers la classe mère et inversement. Ce transtypage comme vous pourrez le constater à la lecture des sources est artificiel, de plus, il nécessite la présence d’une instance de la classe « ClasseMere ». En effet, la macro-fonction « ClasseMereUpCast » se contente d’affecter à chaque les donnée membre de l’instance de la classe « ClasseMere » la valeur de son équivalent dans la classe fille. La macro fonction « ClasseMereDownCast », fait le même type d’affectations mais dans le sens inverse (de l’instance de la classe mère vers l’instance de la classe fille). Ces transtypages, aussi artificiels soient ils, n’empêcheront pas, à priori, le compilateur de détecter les éventuels problèmes de type.
On peut bien évidement utiliser des macros-fonctions pour factoriser du code dans quasiment toutes les fonctions présentes dans les fichiers d’implémentation (pour alléger le code du constructeur par exemple).
Classemere.h :
#ifndef CLASSEMERE_H_INCLUDED
#define CLASSEMERE_H_INCLUDED
typedef struct ClasseMere *ClasseMere;
typedef struct DescripteurClasseMere DescripteurClasseMere;
struct DescripteurClasseMere
{
void (*supprimer)(ClasseMere);
double (*methode1)(ClasseMere a, double);
char*(*methode2)(ClasseMere a,int b, char *c);
};
struct ClasseMere
{
int monChamp1;
double monChamp2;
char* monChamp3;
DescripteurClasseMere* classe;
};
extern ClasseMere
ClasseMere_creer(int champ1, double champ2, char * champ3);
#define ClasseMereUpCast(instance,instanceSousClasse) \
instance->monChamp1=instanceSousClasse->monChamp1; \
instance->monChamp2=instanceSousClasse->monChamp2; \
instance->monChamp3=instanceSousClasse->monChamp3;
#define ClasseMereDownCast(instance,instanceSousClasse) \
instanceSousClasse->monChamp1=instance->monChamp1; \
instanceSousClasse->monChamp2=instance->monChamp2; \
instanceSousClasse->monChamp3=instance->monChamp3;
#endif // CLASSEMERE_H_INCLUDED
classemereimpl.h :
#ifndef CLASSEMEREIMPL_H_INCLUDED
#define CLASSEMEREIMPL_H_INCLUDED
#define ClasseMere_methode1_IMPL(instanceClasseMere, unDouble) \
return instanceClasseMere->monChamp2 + (unDouble);
#define ClasseMere_methode2_IMPL( instanceClasseMere, unInt,unCharEtoile) \
if(strlen(unCharEtoile) > (unInt)){\
return unCharEtoile;\
}\
return instanceClasseMere->monChamp3;
#define ClasseMere_supprimer_IMPL(instanceClasseMere) \
if(instanceClasseMere!=NULL){\
free(instanceClasseMere);\
}
#endif // CLASSEMEREIMPL_H_INCLUDED
classemere.c :
#include
#include
#include
#include "classemere.h"
#include "classemereimpl.h"
static void ClasseMere_supprimer(ClasseMere maClasse){
ClasseMere_supprimer_IMPL(maClasse);
}
static double
ClasseMere_methode1(ClasseMere maClasse,double unDouble){
ClasseMere_methode1_IMPL(maClasse,unDouble);
}
static char *
ClasseMere_methode2(ClasseMere maClasse,int unInt, char * unCharEtoile){
ClasseMere_methode2_IMPL(maClasse,unInt,unCharEtoile);
}
static DescripteurClasseMere*
ClasseMere_obtenir_descripteur(){
static int descripteurDejaInitalise=0; // superieur a 0 si le descripteur est deja initalise
static DescripteurClasseMere descripteur;
if(descripteurDejaInitalise==0){
descripteur.supprimer=ClasseMere_supprimer;
descripteur.methode1=ClasseMere_methode1;
descripteur.methode2=ClasseMere_methode2;
descripteurDejaInitalise++;
}
return &descripteur;
}
ClasseMere
ClasseMere_creer(int champ1, double champ2, char * champ3)
{
ClasseMere monInstance=malloc(sizeof(struct ClasseMere));
monInstance->monChamp1=champ1;
monInstance->monChamp2=champ2;
monInstance->monChamp3=champ3;
monInstance->classe=ClasseMere_obtenir_descripteur();
return monInstance;
}
classefille.h:
#ifndef CLASSEFILLE_H_INCLUDED
#define CLASSEFILLE_H_INCLUDED
typedef struct ClasseFille *ClasseFille;
typedef struct DescripteurClasseFille DescripteurClasseFille;
struct DescripteurClasseFille
{
void (*supprimer)(ClasseFille);
double (*methode1)(ClasseFille a, double);
char*(*methode2)(ClasseFille a,int b, char *c);
int (*methode3)(ClasseFille a,int b);
double (*methode4)(ClasseFille a,int b, double c);
};
struct ClasseFille
{
int monChamp1;
double monChamp2;
char* monChamp3;
int monChamp4;
double monChamp5;
DescripteurClasseFille* classe;
};
extern ClasseFille
ClasseFille_creer(int champ1, double champ2, char * champ3,int champ4,double champ5);
#define ClasseFilleUpCast(instance,instanceSousClasse) \
instance->monChamp1=instanceSousClasse->monChamp1; \
instance->monChamp2=instanceSousClasse->monChamp2; \
instance->monChamp3=instanceSousClasse->monChamp3; \
instance->monChamp4=instanceSousClasse->monChamp4; \
instance->monChamp5=instanceSousClasse->monChamp5;
#define ClasseFilleDownCast(instance,instanceSousClasse) \
instanceSousClasse->monChamp1=instance->monChamp1; \
instanceSousClasse->monChamp2=instance->monChamp2; \
instanceSousClasse->monChamp3=instance->monChamp3; \
instanceSousClasse->monChamp4=instance->monChamp4; \
instanceSousClasse->monChamp5=instance->monChamp5;
#endif // CLASSEFILLE_H_INCLUDED
classefilleimpl.h :
#ifndef CLASSEFILLEIMPL_H_INCLUDED
#define CLASSEFILLEIMPL_H_INCLUDED
#include "classemereimpl.h"
#define ClasseFille_methode3_IMPL(instanceClasseFille,b) \
return a->monChamp4 + (b);
#define ClasseFille_methode4_IMPL(instanceClasseFille,b,c) \
return a->monChamp5 + (c) + ((double) b);
#endif // CLASSEFILLEIMPL_H_INCLUDED
classefille.c :
#include
#include
#include
#include "classefille.h"
#include "classefilleimpl.h"
static void ClasseFille_supprimer(ClasseFille maClasse){
ClasseMere_supprimer_IMPL(maClasse);
}
static double
ClasseFille_methode1(ClasseFille maClasse,double unDouble){
ClasseMere_methode1_IMPL(maClasse,unDouble);
}
static char *
ClasseFille_methode2(ClasseFille maClasse,int unInt, char * unCharEtoile){
ClasseMere_methode2_IMPL(maClasse,unInt,unCharEtoile);
}
static int
ClasseFille_methode3(ClasseFille a,int b){
ClasseFille_methode3_IMPL(a,b);
}
static double
ClasseFille_methode4(ClasseFille a,int b, double c){
ClasseFille_methode4_IMPL(a,b,c);
}
static DescripteurClasseFille*
ClasseFille_obtenir_descripteur(){
static int descripteurDejaInitalise=0; // superieur a 0 si le descripteur est deja initalise
static DescripteurClasseFille descripteur;
if(descripteurDejaInitalise==0){
descripteur.supprimer=ClasseFille_supprimer;
descripteur.methode1=ClasseFille_methode1;
descripteur.methode2=ClasseFille_methode2;
descripteur.methode3=ClasseFille_methode3;
descripteur.methode4=ClasseFille_methode4;
descripteurDejaInitalise++;
}
return &descripteur;
}
ClasseFille
ClasseFille_creer(int champ1, double champ2, char * champ3,int champ4,double champ5)
{
ClasseFille monInstance=malloc(sizeof(struct ClasseFille));
monInstance->monChamp1=champ1;
monInstance->monChamp2=champ2;
monInstance->monChamp3=champ3;
monInstance->monChamp4=champ4;
monInstance->monChamp5=champ5;
monInstance->classe=ClasseFille_obtenir_descripteur();
return monInstance;
}
dimanche 7 décembre 2008
Le C orienté objet, 1ère partie
Le langage de monsieur Stroustrup n’a pas pu enterrer le langage C, ce dernier est encore très utilisé nonobstant son retard par rapport aux langages « modernes » (C++, C#, F# etc.). Aujourd’hui encore, de volumineux logiciels sont faits en langage C, comme les noyaux de la plupart des systèmes d’exploitation modernes (Linux, NetBSD etc.). On peut imaginer qu’a certains moments, dans de gros logiciels écrit en C, le besoin d’utiliser quelques principes de programmation orienté objet se fassent sentir. Comment implémenter des objets en langage C ? C’est justement la question a la quelle cet article essai de répondre.
Définition d’une classe :
Pour cette partie je m’inspirerais des travaux de M. Braquelaire.
Les classes n’existant pas en langage C, nous utiliserons des structures, ces structures contiendront des données membres et des pointeurs de fonctions, qui pointent vers les méthodes de notre classe. Les méthodes de cette « classe » auront toutes au moins un paramètre : l’instance de la classe à laquelle elle s’applique. J’en conviens, il est assez ennuyeux de toujours passer ce paramètre mais n’oubliez pas que nous n’avons pas de « this » en C. Autre point à préciser, il sera nécessaire d’initialiser les pointeurs de fonctions de notre instance dans notre « constructeur ».
Example avec la « classe » « MaClasse » ;
Le fichier d’en-tête :
#ifndef MACLASSE_H_INCLUDED
#define MACLASSE_H_INCLUDED
typedef struct MaClasse *MaClasse;
struct MaClasse
{
int monChamp1;
double monChamp2;
char* monChamp3;
void (*supprimer)(MaClasse);
double (*methode1)(MaClasse, double);
char*(*methode2)(MaClasse,int b, char *c);
};
extern MaClasse
MaClasse_creer(int champ1, double champ2, char * champ3);
#endif // MACLASSE_H_INCLUDED
Le fichier d’implémentation :
#include "maclasse.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static void MaClasse_supprimer(MaClasse maClasse){
if(maClasse!=NULL){
free(maClasse);
}
}
static double
MaClasse_methode1(MaClasse maClasse,double unDouble){
return maClasse->monChamp2 + unDouble;
}
static char *
MaClasse_methode2(MaClasse maClasse,int unInt, char * unCharEtoile){
if(strlen(unCharEtoile) > unInt){
return unCharEtoile;
}
return maClasse->monChamp3;
}
MaClasse
MaClasse_creer(int champ1, double champ2, char * champ3)
{
MaClasse monInstance=malloc(sizeof(struct MaClasse));
monInstance->monChamp1=champ1;
monInstance->monChamp2=champ2;
monInstance->monChamp3=champ3;
monInstance->supprimer=MaClasse_supprimer;
monInstance->methode1=MaClasse_methode1;
monInstance->methode2=MaClasse_methode2;
return monInstance;
}
Comme vous avez pu le constater, la programmation style « objet » en C est un tantinet plus pénible que dans un vrai langage orienté objet. Aussi, il ne vous aura pas échappé que chaque objet embarque trois pointeurs de fonctions en plus des trois données membres. Etant donnée que les trois méthodes sont communes à toutes les instances de la classe « MaClasse » ont peut réduire la taille (en mémoire) des instances en mettant ces pointeurs de fonctions dans un descripteur de classe. Qu’est-ce qu’un descripteur de classe ? Et bien, il s’agit d’une structure qui contient que des pointeurs de fonctions, ces pointeurs de fonctions pointent vers les méthodes qui seront utilisées par toutes les instances de la classe. Cette petite optimisation à l’inconvénient de rallonger l’écriture de l’appel d’une méthode.
Example avec la « classe » « MonAutreClasse » ;
Le fichier d’en-tête :
#ifndef MONAUTRECLASSE_H_INCLUDED
#define MONAUTRECLASSE_H_INCLUDED
typedef struct MonAutreClasse *MonAutreClasse;
typedef struct DescripteurMonAutreClasse DescripteurMonAutreClasse;
struct DescripteurMonAutreClasse
{
void (*supprimer)(MonAutreClasse);
double (*methode1)(MonAutreClasse a, double);
char*(*methode2)(MonAutreClasse a,int b, char *c);
};
struct MonAutreClasse
{
int monChamp1;
double monChamp2;
char* monChamp3;
DescripteurMonAutreClasse* classe;
};
extern MonAutreClasse
MonAutreClasse_creer(int champ1, double champ2, char * champ3);
#endif // MONAUTRECLASSE_H_INCLUDED
Le fichier d’implémentation :
#include "monautreclasse.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static void MonAutreClasse_supprimer(MonAutreClasse maClasse){
if(maClasse!=NULL){
free(maClasse);
}
}
static double
MonAutreClasse_methode1(MonAutreClasse maClasse,double unDouble){
return maClasse->monChamp2 + unDouble;
}
static char *
MonAutreClasse_methode2(MonAutreClasse maClasse,int unInt, char * unCharEtoile){
if(strlen(unCharEtoile) > unInt){
return unCharEtoile;
}
return maClasse->monChamp3;
}
static DescripteurMonAutreClasse*
MonAutreClasse_obtenir_descripteur(){
static int descripteurDejaInitalise=0; // superieur a 0 si le descripteur est deja initalise
static DescripteurMonAutreClasse descripteur;
if(descripteurDejaInitalise==0){
descripteur.supprimer=MonAutreClasse_supprimer;
descripteur.methode1=MonAutreClasse_methode1;
descripteur.methode2=MonAutreClasse_methode2;
descripteurDejaInitalise++;
}
return &descripteur;
}
MonAutreClasse
MonAutreClasse_creer(int champ1, double champ2, char * champ3)
{
MonAutreClasse monInstance=malloc(sizeof(struct MonAutreClasse));
monInstance->monChamp1=champ1;
monInstance->monChamp2=champ2;
monInstance->monChamp3=champ3;
monInstance->classe=MonAutreClasse_obtenir_descripteur();
return monInstance;
}
Vous vous demandez probablement pourquoi je défini les structures dans les interfaces (les fichiers d’en-tête), car vous avez peut-être entendu je ne sais quel programmeur C vous dire qu’en agissant de la sorte vous exposiez l’implémentation aux autres programmeurs. Sachez toutefois que de manière générale, en C++ les classes sont définies dans les fichiers d’en-tête, certes, cette habitude n’est probablement pas bonne, en effet, les données privées sont elles aussi exposées (l’idéal aurait été qu’il soit possible de définir une classe sur deux fichiers comme en C#, une définition publique contenant tout ce dont les autres développeurs ont besoins, et une autre privé, contenant uniquement les données membres et les fonctions privées), mais comment les développeurs peuvent connaitre les méthodes de nos « classes » si les structures ne sont pas définies dans les interfaces ? Certes nous exposons les données membres, mais ne pouvant gérer la visibilité des variables (les champs des structures (les variables d’instances) sont tous publics) il me semble difficile de faire autrement. Nous pouvons en déduire que les accesseurs sont içi inutiles.
Là encore, nous nous trouvons confronté aux faiblesses du langage C.
