Cette classe est normalement invisible en tant que telle a l'utilsateur de la bibliotheque de classes Batch. Mais il est tout de meme utile de la presenter car son action est visible, notamment dans son interaction fine avec la classe Parametre. See Classe Parametre.
Comme il a ete precise dans la descrption de la classe Parametre, la classe Versatile a ete concue pour encapsuler les valeurs de la map Parametre qui peuvent etre de types effectifs differents.
Ces types, decrits par l'enumeration DiscriminatorType, sont actuellement au nombre de trois : long, string et couple. Ces types correpondent au types de base du langage C++ ou de la biliotheque de classes Batch. See Types de base.
Le type special undefined ne sert que pour l'objet Versatile juste cree mais non encore affecte d'une valeur et donc d'un type. La premiere affection d'une valeur a un objet Versatile non encore affecte lui donne automatiquement le type de la valeur.
Les objets de classe Versatile peuvent se comporter soit comme des variables scalaires, c'est-a-dire ne contenant qu'une valeur unique, soit comme des listes, auquel cas elles utilisent l'interface des list de la STL. Toutefois afin de faciliter l'ecriture pour l'utilisateur basique de la classe Versatile — et de la classe Parametre —, des operateurs de concatenation ‘+=’ et ‘,’ ont ete ajoutes.
// Les types autorises enum DiscriminatorType { UNDEFINED, LONG, STRING, COUPLE }; typedef struct { DiscriminatorType type; // le type de l'element interne int maxelem; // le nombre d'elements autorises } TypeParam; class Versatile : public list< GenericType * > { public: // Constructeur standard et destructeur Versatile(); virtual ~Versatile(); // Constructeur par recopie Versatile(const Versatile & V); // Constructeur depuis le type de "base" Versatile(long l); Versatile(const string & s); Versatile(const Couple & c); // Operateur d'affectation et de concatenation // a partir d'un type de "base" Versatile & operator = (const long l) throw(TypeMismatchException); Versatile & operator = (const string & ch) throw(TypeMismatchException); Versatile & operator +=(const string & ch) throw(TypeMismatchException,ListIsFullException); Versatile & operator , (const string & ch) throw(TypeMismatchException,ListIsFullException); Versatile & operator = (const Couple & cp) throw(TypeMismatchException); Versatile & operator +=(const Couple & cp) throw(TypeMismatchException,ListIsFullException); Versatile & operator , (const Couple & cp) throw(TypeMismatchException,ListIsFullException); // Operateur d'affectation entre objets Versatile & operator = (const Versatile & V) throw(TypeMismatchException); // Conversion de type vers un type de "base" operator long() const throw(TypeMismatchException); operator string() const throw(TypeMismatchException); operator Couple() const throw(TypeMismatchException); string str() const throw(TypeMismatchException); // Operateur pour l'affichage sur un stream friend ostream & operator << (ostream & os, const Versatile & ); // Positionnement et recuperation du type de l'element interne void setType(DiscriminatorType) throw(TypeMismatchException); DiscriminatorType getType() const; // Positionnement et recuperation du nombre d'elements internes void setMaxSize(int i); int getMaxSize() const; // Positionnement et recuperation du nom de l'objet string getName() const; void setName(const string & name); protected: // Efface tous les elements internes de l'objet virtual void eraseAll(); DiscriminatorType _discriminator; // type de l'element interne int _maxsize; // nombre max d'elements internes string _name; // nom de l'objet (sert pour les exceptions) private: };
... // On cree un objet Versatile non encore affecte (scalaire) Versatile Vlong; // L'affectation d'un long lui donne le type LONG Vlong = 1024L * 1024L * 1024L; cout << "Versatile long (must be 1073741824) : " << Vlong << endl; // On cree un objet Versatile non encore affecte (scalaire) Versatile Vstring; // L'affectation d'une string (const char * promu en string) // lui donne le type STRING Vstring = "UneChaine"; cout << "Versatile string (must be UneChaine) : " << Vstring << endl; try { // L'affectation d'un autre type leve une exception. // Il n'y a pas de retypage dynamique. Vlong = ""; cout << "ERR : No TypeMismatchException catched for Versatile long" << endl; } catch (TypeMismatchException & ex) { cout << "OK : TypeMismatchException catched for Versatile long" << endl; } // Reaffectation avec le meme type Vlong = 1024L * 1024L; cout << "Versatile long (must be 1048576) : " << Vlong << endl; // On cree un objet Versatile non encore affecte (scalaire) ... Versatile Vcat1; // ... que l'on transforme en liste (non limitee) Vcat1.setMaxSize(0); // On affecte la premiere valeur ... Vcat1 = "A"; // ... puis les suivantes par concatenation Vcat1 += "B"; Vcat1 += "C"; Vcat1 += "D"; Vcat1 += "E"; cout << "Versatile string concatenation (must be A B C D E) : " << Vcat1 << endl; // Idem que pour Vcat1, mais avec une limite a 5 elements dans la liste Versatile Vcat2; Vcat2.setMaxSize(5); Vcat2 = "a", "b", "c", "d", "e"; cout << "Versatile string concatenation (must be a b c d e) : " << Vcat2 << endl; // On tronque les 2 derniers elements de la liste (il en reste 3) Vcat2.setMaxSize(3); cout << "Versatile string concatenation (must be a b c) : " << Vcat2 << endl; Versatile Vcopy2(Vcat2); cout << "Versatile copy (must be a b c) : " << Vcopy2 << endl; Versatile Vaffect; Vaffect = Vcat1; cout << "Versatile affect (must be A B C D E) : " << Vaffect << endl; Vaffect = Vcat2; cout << "Versatile affect (must be a b c) : " << Vaffect << endl; try { // Retypage dynamique interdit Vaffect = Vlong; cout << "ERR : No TypeMismatchException catched for Versatile" << endl; } catch (TypeMismatchException & ex) { cout << "OK : TypeMismatchException catched for Versatile string" << endl; } try { // Concatenation au dela de la limite interdit Vcat2 += "En trop"; cout << "ERR : No ListIsFullException catched for Versatile string" << endl; } catch (ListIsFullException & ex) { cout << "OK : ListIsFullException catched for Versatile string" << endl; } // Les objets Versatile se comportent (presque) comme des objets // standards du langage long L = Vlong; cout << "Long value of Versatile long (must be 1048576) : " << L << endl; string S = Vstring; cout << "String value of Versatile (must be EncoreUneAutreChaine):" << S << endl; ...
Le constructeur par defaut fabrique un objet scalaire de type undefined et de nom ‘undefined’.
Le destructeur efface tout le contenu de l'objet si celui-ci avait ete affecte.
Le constructeur par recopie duplique l'objet passe en argument ainsi que les valeurs qu'il contient. Le nouvel objet est totalement independant de son geniteur.
Ces constructeurs fabriquent des objets scalaires Versatile a partir des types de base passes en argument. Chaque objet acquerera definitivement le type correspondant au type de base : long pour ‘long’, string pour ‘string’ et couple pour ‘Couple’.
Ces operateurs affectent ou reaffectent la valeur passee en argument a l'objet. Le type de la valeur doit correspondre au type de l'objet si celui-ci a deja ete affecte, sinon une exception TypeMismatchException est levee. See Classe TypeMismatchException.
L'ancienne valeur de l'objet est perdue.
Ces operateurs concatenent la valeur passee en argument a l'objet. Le type de la valeur doit correspondre au type interne de l'objet si celui-ci a deja ete affecte, sinon une exception TypeMismatchException est levee. See Classe TypeMismatchException.
Si la taille maximale de la liste est depasse, une exception ListIsFullException est levee. See Classe ListIsFullException.
L'operateur d'affectation duplique l'objet passe en argument dans l'objet. Toutes les valeurs internes sont dupliquees de maniere a avoir une independance totale entre les deux objets a l'issue de l'affectation.
Il est a noter qu'il est possible d'affecter a un objet un objet possedant un type different, auquel cas l'objet courant change de type pour acquerir celui de l'objet passe en argument. C'est le seul cas de changement de type autorise pour un objet.
Ces operateur de conversion dans les types de base permettent de recuperer la valeur interne de l'objet. Lorsque le type interne est incompatible avec la conversion une exception TypeMismatchException est levee. See Classe TypeMismatchException.
Cet operateur permet de voir le contenu de l'objet sur un flot de sortie.
Cette methode change le type interne de l'objet en celui passe en argument. Ceci n'est possible que pour un objet non encore affecte. Si le nouveau type est different du type actuel une exception TypeMismatchException est levee. See Classe TypeMismatchException.
Cet accesseur renvoie le type interne de l'objet.
Cette methode permet de changer le nombre d'elements que l'objet est capable de stocker. Par defaut ce nombre est 1 a la construction de l'objet, signifiant qu'il ne peut contenir qu'une seule valeur a la fois (scalaire).
Si ce nombre est superieur a 1 alors il represente une limite qui ne pourra etre depassee par l'objet sans lever d'exception ListIsFullException. See Classe ListIsFullException.
Si ce nombre vaut 0 (zero) alors il n'y a aucune limite superieure au nombre d'element dans l'objet.
Cet accesseur renvoie la taille maximale admise par l'objet.
Cette methode permet de positionner le nom de l'objet. Par defaut ce nom vaut ‘undefined’ a la construction de l'objet.
Il est interessant de positionner le nom a une valeur significative comme par exemple le nom de la variable contenant l'objet car lorsqu'une exception est levee ce nom apparait en clair et aide au debugging.
Cet accesseur renvoie le nom interne de l'objet.