Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - création d'une classe BOOPSI
(Article écrit par Eric Totel et extrait d'Amiga News - mars 1996)
|
|
Pour illustrer le précédent article, nous allons réaliser cette fois une
classe BOOPSI élémentaire. Son but est uniquement éducatif. En effet, peu de personnes pourront, à mon avis, en trouver une
utilisation pratique, sauf peut-être des gens ayant besoin d'une gestion dynamique des chaînes (ce qui peut d'ailleurs être
réalisé sans utiliser BOOPSI !).
Notre classe comporte la définition d'une méthode (outre les méthodes fondamentales) STM_Concat (concaténation de notre chaîne
et d'une chaîne de caractère C classique) et d'un attribut STA_Content (contenu de notre chaîne) qui peut être défini à
l'initialisation, lu (GetAttr), et écrit (SetAttr). L'application de la méthode STM_Concat modifie également l'attribut STA_Content.
Notre classe effectue systématiquement une copie des chaînes qu'on lui passe.
Les éléments à retenir dans cet exemple sont sans aucun doute :
- La création d'une classe publique (InitStringClass). Vous noterez que dans notre exemple, le fait que la classe soit publique
est inutile : une classe privée aurait parfaitement fait l'affaire.
- La destruction d'une classe publique (DisposeStringClass).
- Le positionnement des attributs : utilisation de la fonction SetAttrs qui correspond à un envoi de la méthode OM_SET et
à l'exécution de la fonction mSetString.
- La lecture d'un attribut : utilisation de GetAttr, c'est-à-dire envoi de la méthode OM_GET et exécution de mGetString.
- On utilise une structure dont la première composante est un ULONG (la méthode reçue par l'objet) pour passer des paramètres
précis à une méthode que l'on crée (ici mConcatString, et la structure utilisée est pConcatString).
- DoSuperMethodA et DoSuperMethod permettent de propager la méthode reçue à la superclasse (classe parente).
- Amusez-vous à ajouter quelques méthodes (par exemple concaténer deux objets BOOPSI String) pour comprendre le
fonctionnement de l'ensemble. Une fois le mécanisme compris, vous disposerez d'un moteur objet extrêmement puissant que vous
pourrez programmer en C.
#include <dos/dos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <exec/memory.h>
#include <stdio.h>
#include <string.h>
#if defined(_DCC)
#define REG(x) __ ## x
#define SAVEDS __geta4
#define ASM
#define REGARGS __regargs
#else
#if defined(__SASC)
#define REG(x) register __ ## x
#define SAVEDS __saveds
#define ASM __asm
#define REGARGS __regargs
#endif
#endif
/* Données de la classe */
struct StringData
{
char *string;
};
/* Paramètre de la méthode Concat */
struct pConcatString
{
ULONG Method;
char *string;
};
/* Bibliothèques utilisées */
struct Library *IntuitionBase;
struct Library *UtilityBase;
/* Définition des attributs et Méthodes */
/* Attributs */
#define STA_Content (TAG_USER + 0)
/* Méthodes */
#define STM_Concat (TAG_USER + 10)
struct IClass *StringClass;
/**********************************/
/* Définition de la classe String */
/**********************************/
/*******************************************/
/* Positionnement des attributs de l'objet */
/*******************************************/
SAVEDS ULONG mSetString(Class *cl, Object *obj, struct opSet * msg)
{
struct StringData *data = INST_DATA(cl, obj);
struct TagItem *ti, *tstate;
ULONG retval = 0;
ULONG size;
retval = DoSuperMethodA(cl, obj, (Msg)msg);
ti = msg->ops_AttrList;
tstate = ti;
while(ti = NextTagItem(&tstate))
{
switch(ti->ti_Tag)
{
case STA_Content:
if (data->string) FreeVec(data->string);
size = strlen((char*)ti->ti_Data);
if (data->string = AllocVec(size+1, MEMF_PUBLIC|MEMF_CLEAR))
{
memcpy(data->string, (char*)ti->ti_Data, size+1);
}
retval = 1L;
break;
}
}
return(retval);
}
/************************************/
/* Lecture des attributs de l'objet */
/************************************/
SAVEDS ULONG mGetString(Class *cl, Object *obj, struct opGet * msg)
{
struct StringData *data = INST_DATA(cl, obj);
ULONG retval = 0;
switch(msg->opg_AttrID)
{
case STA_Content:
*(msg->opg_Storage) = (ULONG) data->string;
retval = 1;
break;
}
if (!retval) DoSuperMethodA(cl, obj, (Msg)msg);
return(retval);
}
/******************************/
/* Création d'un nouvel objet */
/******************************/
SAVEDS ULONG mNewString(Class *cl, Object *obj, struct opSet *msg)
{
struct StringData *data = NULL;
ULONG retval = 0;
char *straux;
ULONG size;
if (retval = DoSuperMethodA(cl, obj, (Msg)msg))
{
data = INST_DATA(cl, retval);
if (data->string = (char*) GetTagData(STA_Content, 0, msg->ops_AttrList))
{
if (straux = AllocVec((size = strlen(data->string))+1, MEMF_PUBLIC|MEMF_CLEAR))
{
memcpy(straux, data->string, size+1);
data->string = straux;
}
}
}
return((ULONG)retval);
}
/**************************/
/* Destruction d'un objet */
/**************************/
ULONG mDisposeString(Class *cl, Object *obj, Msg msg)
{
struct StringData *data = INST_DATA(cl, obj);
if (data->string) FreeVec(data->string);
return(DoSuperMethodA(cl, obj, msg));
}
/****************************************************/
/* Concatenation d'une string et d'une chaine char* */
/****************************************************/
SAVEDS ULONG mConcatString(Class *cl, Object *obj, struct pConcatString *msg)
{
struct StringData *data = INST_DATA(cl, obj);
char *straux;
ULONG size;
straux = data->string;
if (msg->string)
{
if ((straux)&&
(data->string = AllocVec(strlen(msg->string)+strlen(straux)+1, MEMF_PUBLIC|MEMF_CLEAR)))
{
sprintf(data->string, "%s%s", straux, msg->string);
FreeVec(straux);
}
else
{
SetAttrs(obj, STA_Content, msg->string, TAG_DONE);
}
}
return(0);
}
/***********************************************************/
/* Fonction Dispatcher : reçoit les méthodes et les traite */
/***********************************************************/
SAVEDS ULONG DispatcherString(struct IClass *cl, Object *obj, Msg msg)
{
APTR retval = NULL;
/* On appelle la méthode désirée */
switch(msg->MethodID)
{
case OM_NEW: return(mNewString(cl, obj, (struct opSet *)msg));
case OM_SET: return(mSetString(cl, obj, (struct opSet *)msg));
case OM_GET: return(mGetString(cl, obj, (struct opGet *)msg));
case OM_DISPOSE: return(mDisposeString(cl, obj, msg));
case STM_Concat: return(mConcatString(cl, obj, (struct pConcatString *)msg));
default:
retval = (APTR)DoSuperMethodA(cl, obj, msg);
break;
}
return((ULONG)retval);
}
/*******************************/
/* Initialisation de la classe */
/*******************************/
BOOL InitStringClass(void)
{
extern ULONG HookEntry();
BOOL retval = FALSE;
/* Creation de la classe */
if (StringClass = MakeClass("StringClass", "modelclass", NULL, sizeof(struct StringData), 0))
{
StringClass->cl_Dispatcher.h_Entry = HookEntry;
StringClass->cl_Dispatcher.h_SubEntry = DispatcherString;
/* On rend la classe publique (pas nécessaire dans notre cas) */
AddClass(StringClass);
retval = TRUE;
}
return(retval);
}
/****************************/
/* Destruction de la classe */
/****************************/
void DisposeStringClass(void)
{
/* On enleve la classe du système (seulement si elle est publique) */
RemoveClass(StringClass);
/* On libère la classe */
FreeClass(StringClass);
}
/*******************************/
/* Fermeture des bibliothèques */
/*******************************/
void Clean(void)
{
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (UtilityBase) CloseLibrary(UtilityBase);
}
/************************************/
/* Fonction principale du programme */
/* Test de la classe String */
/************************************/
int main(void)
{
APTR MyString;
char *straux;
/* Initialisations des bibliothèques */
if (!(IntuitionBase = OpenLibrary("intuition.library", 0)))
{
Clean();
return(20);
}
if (!(UtilityBase = OpenLibrary("utility.library", 0)))
{
Clean();
return(20);
}
/* Initialisation de la classe boopsi */
if (!InitStringClass())
{
Clean();
return(20);
}
/* Test de l'objet */
if (MyString = NewObject(NULL, "StringClass",
STA_Content, "Essai",
TAG_DONE))
{
/* Test du get */
GetAttr(STA_Content, MyString, (ULONG*)&straux);
printf ("Actuellement MyString = %s\n", straux);
/* Test du set */
SetAttrs(MyString, STA_Content, "Essai2", TAG_DONE);
GetAttr (STA_Content, MyString, (ULONG*)&straux);
printf ("Actuellement MyString = %s\n", straux);
/* Test du STM_Concat */
DoMethod(MyString, STM_Concat, " - Juste pour tester");
GetAttr (STA_Content, MyString, (ULONG*)&straux);
printf ("Actuellement MyString = %s\n", straux);
/* Effacement de l'objet */
DisposeObject(MyString);
}
/* Détruit la classe string */
DisposeStringClass();
Clean();
return(0);
}
|
|