Modes de création d'instances d'entités
Il existe au moins trois manières de créer des instances d'Entity.
- La manière la plus simple consiste à invoquer directement un constructeur quelconque de la classe pour laquelle on désire créer une instance.
A* p = new A([argument_list]);- Les fichiers UserFunction.h et .cc peuvent contenir l'entête et la réalisation de fonctions plus ou moins élaborées de création d'instances, spécifiques des différentes sous-classes d'Entity. Elles renvoient un pointeur sur l'instance créée, sous la forme d'un pointeur d'instance de la classe considérée.
A* CreateA(argument_list) { A* p = new A(); ... return p; }Outre l'appel au constructeur de la classe, une telle fonction ... :
- ... peut contenir des instructions de trace de la création (voir le commentaire de la fonction ParseMainArguments, page 'Interprétation des arguments de la commande de simulation') :
... if(gTraceNewDelMode) printf("\n+Construction du %d %x", p->ClassId(), p);- ... permet de donner des valeurs particulières aux attributs de l'instance créée (les valeurs sont alors passées en arguments : il s'agit donc d'une construction paramétrée) :
A* CreateA(float xval, char* name) { A* p = new A(); int descId = AREA; p->GetConstantDescriptor(descId)->SetDefaultValue(xval); p->InstanceName(name); ... }- ... permet d'enchasser la construction des composants de l'entité créée, par appel à une fonction de création ou au constructeur de la classe :
A* CreateA(float xval, char* name) { A* p = new A(); AElem* pObj = new AElem(); p->AddElement(pObj); ... }
- Le fichiers UserFunction.h et .cc peuvent, en général, et doivent dans des cas particuliers (voir plus loin) contenir en outre l'entête et la réalisation de la fonction App_NewEntityFromString, qui renvoie une instance d'entité (plus précisément un pointeur sur cette instance) à partir du nom d'une classe d'Entity ; dans ce cas, une invocation de Assign_App_NewEntityFromStringFunction affecte la fonction utilisateur comme valeur du pointeur sur fonction pApp_NewEntityFromString}
La fonction utilisateur doit être programmée de telle sorte qu'elle invoque le constructeur sans argument de la classe dont le symbole ou le nom de classe est passé en argument, et qu'elle renvoie l'instance créée, sous la forme d'un pointeur d'instance d'Entity, ou bien le pointeur NULL si aucune instanciation n'a pu être faite.
Entity* App_NewEntityFromString(char* s) \{} Entity* pInst = NULL; if(! strcmp(s, "a") pInst = new A(); if(! strcmp(s, "b") pInst = new B(); ... return pInst; }Le même principe s'applique à la création d'instances de Process, d'Event et de DescValueSpec, plus précisément de sous-classes propres à l'application. La fonction appropriée est alors App_NewProcessFromStringFunction pour les processus,
App_NewEventFromStringFunction pour les événements, et [/]App_NewDescValueSpecFromStringFunction pour les spécifications de domaines de valeur. Il s'applique aussi à la création d'instances de SerialDataFile avec la fonction App_NewSerialDataFileFromStringFunction.
Par invocation d'une fonction d'assignation appropriée (de nom AssignNew..Function, parmi celles définies ci-dessous), les fonctions 'utilisateur' deviennent les valeurs des fonctions d'intantiation prédéfinies de DIESE pApp_NewEntityFromString , pApp_NewProcessFromStringFunction, , elles aussi définies ci-dessous.
Les appels aux fonctions Assign_App_New..Function peuvent être inclus dans la fonction
App_AssignInstantiators, déclarée dans DIESE, mais obligatoirement réalisée dans les fichiers UserFunction de l'application. En tout état de cause, ces fonctions doivent être invoquées avant toute invocation des fonctions prédéfinies de DIESE correspondantes. Même si ces fonctions ne sont jamais invoquées, on doit déclarer et réaliser une fonction App_AssignInstantiators avec un corps éventuellement vide.
Les cas particuliers necéssitant l'existence de fonctions d'instanciation sont les suivants.
- Ces fonctions sont invoquées lors de la lecture et l'interprétation du fichier de déclaration de la structure du système simulé (voir page 'Le fichier de description de la structure du système'). En conséquence, si le code de l'application (typiquement dans son main()) contient un appel de ParseStructureFile, il est nécessaire d'invoquer au préalable les fonctions d'assignation. Noter à ce propos que l'interprétation du fichier de spécification de la simulation invoque la fonction App_AssignInstantiators lors de l'instanciation de la simulation courante. Il suffit alors d'avoir inclus les appels aux fonctions d'instanciation dans le code de App_AssignInstantiators.
- La méthode Expand de la classe EntitySpec génère une liste d'entités satisfaisant une certaine spécification. Si le mode de création de la liste demande de lister des instances non pas déjà existantes, mais à créer, alors Expand invoque la fonction pApp_NewEntityFromId.
Le code de la fonction App_AssignInstantiators sera normalement le suivant :
void App_AssignInstantiators() { Assign_App_NewEntityFromStringFunction(App_NewEntityFromString); Assign_App_NewEntityFromIdFunction(App_NewEntityFromId); Assign_App_NewProcessFromStringFunction(App_NewProcessFromString); Assign_App_NewEventFromStringFunction(App_NewEventFromString); Assign_App_NewEntitySpecFunction(App_NewEntitySpecFromString); Assign_App_NewDescValueSpecFunction(App_NewDescValueSpecFromString); Assign_App_NewSerialDataFileFunction(App_NewSerialDataFileFromString); Assign_App_NewSerialDataFileFromIdFunction(App_NewSerialDataFileFromId); Assign_App_SerialDataFileIdFromStringFunction(App_SerialDataFileIdFromString); };[P/]