mardi 23 octobre 2012

Les tableaux en Javascript


Le tableau qui suit a été entièrement conçu avec Javascript et n'a pas nécessité plus de 6 lignes de code ! Il s'agit d'un petit "agenda" très simple destiné à servir de pense-bête pour les grandes occasions à venir (j'ai simplifié au maximum en utilisant une entrée pour les mois, une pour la personne concernée et une autre pour le motif de la réunion familiale.
Avec HTML, il aurait fallu plus du double de lignes voire le triple pour écrire les <tr> et les <td>, les bgcolor des <td>, le bgcolor de la <table>...


janvier
andré
anniversaire
fevrier
monique
fête
mars
natacha
baptême
avril
meryl
dentiste
mai
julie
baptême
juin
arthur
rendez-vous
juillet
grand-père
noce d'or
aout
oncle tom
bac
septembre
julien
concours
octobre
cosette
barbecue
novembre
marcel
visite
decembre
rené
séjour ski

Outre la compacité du code, l'avantage indéniable de ce tableau en Javascript, c'est sa modularité exemplaire : modifier, compléter ou supprimer une ligne ou une cellule est un jeu d'enfant...
Pour aboutir à ce tableau, quelques notions "avancées" sont nécessaires : vous allez voir ce qu'est un "array" et par la suite ce qu'est une boucle...
** Un Array est en fait une collection d'informations dans laquelle chaque information est indicée. Admettons que vous soyez très riche et que dans votre garage, vous avez entreposé 5 voitures. Le garage en Javascript s'appelle "Array" et chaque voiture est un élément de l'Array.
Pourquoi élément indicé ? Parce que pour plus de praticité et de "portabilité", vos voitures ne sont pas nommées par Renault, Citroen ou Mercedes mais par leur position, leur indice dans l'Array.
Exemple :

<script>
var garage=new Array(5)
garage[0]="renault"
garage[1]="citroen"
garage[2]="mercedes"
garage[3]="seat"
garage[4]="peugeot"
Ici l'array ne comporte que 5 éléments référencés de "0" pour le premier à "4" pour le cinquième. Pensez à notre ère "judéo-chrétienne" qui commence elle-aussi à l'an 0 ! Cette manière de procéder est bien mais si vous êtes très très riche, vous allez avoir, disons 60 voitures...
Il serait très fastidieux d'écrire de garage[0] à garage [59] donc je vous conseille la syntaxe suivante beaucoup plus simple et tout aussi efficace :

var garage=new Array("renault","citroen","mercedes","seat","peugeot")
Le résultat sera le même et vous aurez gagné du temps !

Oui mais ça sert à quoi les Arrays ? Vous allez en avoir un aperçu...


    



Voici le code de la fonction montre(), fonction que j'ai placée dans le <head> de la page HTML :
<script>
function montre(i)
{
var garage=new Array("renault","citroen","mercedes","seat","peugeot")
document.forme.champ.value="cette voiture est une "+garage[i]+" !"
}
</script>


et le code pour les boutons :

<input type="button" value="mon auto" onclick="javascript:montre(0)">
<input type="button" value="ma voiture" onclick="javascript:montre(1)">

etc, etc,...
Je conviens que pour l'instant cet exemple n'est pas très folichon mais comprenez que par la suite, dans vos arrays vous pourrez mettre des images, des pop-ups, pratiquement tout ce qui vous passera par la tête...
Un autre exemple "parlant" vous donnera peut-être plus d'idées :

Dire
Adieu !


Cet effet est obtenu par l'utilisation d'un array, d'un div et de la fonction feu() :
<script>
var mot=new Array("Salut !","bonjour !","au revoir !","à bientôt...","Adieu !")
function feu(i){
document.getElementById('mon_div').innerText=mot[i];}
</script>



et le code du <div> :
<a href="#" onmouseover="feu(0)" onmouseout="feu(4)">Dire</a>
<div id=mon_div style="width:60;height:20;border-color: #d9d9f3;background:#d9d9f3;font-family:verdana;font-size:20px;color:#8f8fbd"></div>

L'array comporte ici 5 éléments indicés (0, 1, 2, 3, 4) qui sont directement nommés par la fonction "feu(0)" et "feu(4)" par l'intermédiaire des event handlers.
Nous avions déjà vu "onclick", qui comme son nom l'indique, déclenche l'action par le clic. "onmouseover" active la fonction au survol de la souris dans la zone du div, et onmouseout lors de la sortie de la souris de cette même zone...
** Pour résumer, un Array permet de stocker des variables et de les utiliser dans un script en les appelant par leur indice.

les bases de la syntaxe


Revenons sur la syntaxe de la fonction longb() écrite dans sa version "académique" et examinons chaque ligne :
<script language="Javascript">
<!--
function longb()
{
var c=document.formeb.champb.value
if (c.length>=3)
{
alert("Bienvenue chez vous !")
}
else
{
alert ("Votre code est erroné !")
}
}
//-->
</script>
La présence de tant d'accolades et de parenthèses peut rebuter mais c'est vraiment très simple :
function longb()
{
Je mets entre les accolades les instructions de ma fonction.
Cela peut être des actions simples ou parfois plus complexes

}


Une condition s'exprime avec "if" :

if (condition)
{
je mets entre les accolades l'instruction à exécuter
si la condition est remplie

}
else sinon
{
je mets entre les accolades l'instruction à exécuter si la condition n'est pas remplie
}
Ce n'est pas une obligation que d'aller à la ligne aprés chaque accolade, mais conseillé pour une meilleure lisibilité et aussi pour éviter les erreurs. Si vous avez 3 accolades ouvrantes, vous devez en avoir 3 autres fermantes !

La notion de Classe (C++)


Nous allons enfin parler, dans ce chapitre, de Programmation Orientée Objet. Nous allons commencer par comprendre le mécanisme des classes.

Ecriture d’une première classe

Une classe est en quelque sorte une structure complexe qui permet l’encapsulation de données.
Une classe est composée de données et de méthodes. Lorsque l’encapsulation des données est parfaite, seules certaines méthodes sont accessibles, devenant ainsi l’interface. Ceci évite en principe à l’utilisateur de la classe, de se soucier de son fonctionnement et de faire des erreurs en changeant directement la valeur de certaines données.
Prenons un exemple concret et simple : l’écriture d’une classe Point. Cet exemple va nous suivre tout au long de ce chapitre. En C, nous aurions fait une structure comme suit :
struct Point
{
     int x;     // Abscisse du point 
     int y;     // Ordonnée 
};


DTD


1.Document valide

Un document XML a besoin d'une DTD pour savoir ce qu'il est possible de faire ou pas.
Si l'on fait la comparaison avec l'HTML, on sait que théoriquement on doit écrire:

<html>
    <head>
    </head>
    <body>
        <table>
            <tr>
                <td>
                </td>
            </tr>
        </table>
    </body>
</html>


et non pas

<html>
    <head>
    </head>
        <table>
                <td>
                </td>
        </table>
</html>


il y a certaines rêgles à respecter même si les navigateurs ont été programmés pour comprendre à peu près n'importe quoi.
Avec la DTD, on va pouvoir décrire de manière stricte la structure du fichier XML. Avec des outils on pourra alors vérifier qu'un fichier XML est "valide" pour une DTD donnée.

2.Un exemple de DTD

Une DTD peut être définie soit à l'intérieur d'un document XML soit dans un fichier à part. Cette dernière solution est la plus fréquente car la plus pratique.
Pour définir une DTD externe, il suffit d'écrire <!DOCTYPE racine SYSTEM "nomdufichier.dtd"> juste après <?xml version="1.0" ?> où racine est le nomde la balise racine de l'arbre XML.
Reprenons notre fichier XML d'exemple et ajoutons-y cette ligne:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE annuaire SYSTEM "annuaire.dtd">
<annuaire>
    <personne type="étudiant">
        <nom>HEUTE</nom>
        <prenom>Thomas</prenom>
        <email>webmaster@xmlfacile.com</email>
    </personne>
    <personne type="chanteur">
        <nom>SOUCHON</nom>
        <prenom>Alain</prenom>
        <email>alain@souchon.name</email>
    </personne>
</annuaire>


<?xml version="1.0" encoding="ISO-8859-1"?>
<!ELEMENT annnuaire     (personne*)>
<!ELEMENT personne  (nom,prenom,email+)>
<!ATTLIST personne type (étudiant | professeur | chanteur | musicien) "étudiant">
<!ELEMENT nom       (#PCDATA)>
<!ELEMENT prenom    (#PCDATA)>
<!ELEMENT email (#PCDATA)>


Voici ce que pourrait-être sa DTD:
  • Pour chacun des éléments, on défini sa composition par <!ELEMENT nom_element (structure)>
  • Pour chacun des attributs, on défini sa composition par <!ELEMENT nom_element nom_attribut (structure)>
  • L'attribut type est, ici, défini comme étant un choix imposé entre "étudiant", "professeur", "chanteur" et "musicien", par défaut on met étudiant (facultatif).
  • personne* signifie que dans un élément annuaire on peut trouver de 0 ou plusieurs éléments de type personne.
  • nom,prenom,email+ signifie que dans un élément personne on doit trouver une élément nom, un élément prenom et un ou plusieurs élément(s) email dans cet ordre.
  • nomprenom et email sont des éléments qui peuvent contenir du texte, les contenus #PCDATA sont dits contenus mixtes
  • Deux autres types pour les éléments existent, EMPTY et ANY, empty signifie que l'élément est vide (comme <br> en HTML), ANY indique que l'élément peut comporter tout autre élément déclaré dans la DTD.

3.La syntaxe

Reprenons les différents indicateurs d'occurences:
  • pas de symbole veut dire 1 et 1 seul élément
  • + veut dire 1 ou plusieurs éléments
  • * veut dire 0 ou plusieurs éléments
  • ? veut dire 0 ou 1 éléments
Ces symbles sont placés juste après les noms des éléments.

Et voici les différents connecteurs possibles:
  • , les différents éléments séparés par une virgule doivent apparaître dans l'ordre donné
  • | signifie qu'un seul des deux éléments séparés par ce symbole doit apparaître dans le fichier XML
Ces symbles sont placés entre deux éléments.
  • On peut composer les différents connecteurs en utilisant les parenthèses. Toutefois, il faut veiller à ne pas définir une gramaire trop ambigüe par exemple ((nom,prenom)|(nom,surnom)) n'est pas correct, il est préférable d'écrire (nom,(prenom|surnom)).
  • On peut autoriser plusieurs éléments répétés, par exemple (adresse,telephone)* ce qui permet de créer des couples (adresse,telephone).
Les attributs (déclarés par ATTLIST) possèdent différents contrôles:
  • CDATA pour une chaîne quelconque de caracères
  • ID pour un nom unique dans le document (identifiant)
  • IDREF pour un numéro d'idantifiant du document (création d'un lien dans le document)
  • ENTITY entité externe
  • ENTITIES liste d'ENTITY séparées par des espaces
  • NMTOKEN pour un mot sans espace
  • NMTOKENS pour une liste de NMTOKEN séparés par des espaces
Les valeurs des attributs peuvent être précisées par la DTD.
  • #REQUIRED signifie que la valeur doit-être donnée dans le document
  • #IMPLIED signifie que s'il n'y a pas de valeur dans le document, c'est à l'application de donner la sienne par défaut
  • #FIXED signifie que la valeur doit être celle de la DTD
  • une valeur par défaut que va prendre l'attribut si aucune valeur n'est donnée dans le fichier XML

4.Conclusion

Il est très important d'avoir une bonne DTD et donc de passer du temps à sa conception. C'est elle qui vous permettra de construire des documents XML valides. Il peut-être aussi astucieux d'utiliser des DTD existantes et éventuellement de les modifier, c'est généralement plus efficace que de tout refaire à 0. Par exemple, il est plus que probable qu'une DTD définissant un annuaire existe déjà et qu'il prend en compte des choses auxquelles vous n'aviez pas pensé comme l'Etat aux USA par exemple.
Jusque là, on a défini une structure qui pourra être utilisés dans de nombreux outils. On peut ainsi stocker des données (dans des fichiers XML) reste à trouver le moyen de les mettre en forme: c'est le rôle entre autres d'XSL.

lundi 22 octobre 2012

Construction, destruction et initialisation d’objets en C


Constructeur par défaut/initialisant

Constructeurs simples

Nous avons abordé précédemment la possibilité d’initialiser un objet lors de sa construction, ou encore de proposer un constructeur par défaut. Nous allons dans ce chapitre généraliser le principe tout en l’approfondissant.
Tout d’abord, il faut bien comprendre l’intérêt de la chose : un constructeur initialisant permet comme son nom l’indique d’initialiser les données membre, que ces valeurs soient entrées par l’utilisateur, ou bien qu’elles soient par défaut. Le destructeur quant à lui est appelé à la fin de la vie de l’objet, de façon automatique ou non (si l’objet est un pointeur).
Ceci prend toute son importance dans le cas d’un objet qui contient lui-même des données de type pointeur. Prenons par exemple une classe Vecteur qui gère un vecteur mémoire d’entiers. Nous allons essayer d’intégrer dans un premier temps :

  • un constructeur initialisant, connaissant la taille du vecteur,
  • un destructeur,
  • une méthode de lecture d’une valeur dans le vecteur,
  • une méthode d’écriture d’une valeur dans le vecteur,
  • une méthode qui renvoie la taille du vecteur.

Dans la mesure où vous devriez être capable de réaliser cette classe, essayez de la concevoir tout seul dans un premier temps...

XSLT


1.Introduction à XSLT

Maintenant que l'on a un fichier XML et qu'il est valide, on va en faire quelque chose. Dans les pages qui vont suivre, nous allons tenter de voir ce que l'on peut faire simplement avec XSLT. XSLT est relativement complexe mais il est aussi très puissant. Avec XSLT on peut faire beaucoup de choses a condition de savoir l'utiliser.
Dans ces pages nous n'allons pas entrer dans les détails simplement parce que nous ne parlerons que de ce que nous connaissons et avons testé.
Ceci dit il est très simple d'assimiler les bases qui permettent déjà de faire des choses intéressantes. Par exemple, sur ce site, les cours sont écrit une seule fois en XML. Deux feuilles de styles différentes permettent de formater les cours page par page ou bien en version imprimable sur une seule page HTML.
Dans les pages suivantes nous allons formater l'annuaire en XML que nous avions dans les chapitres précédents.

2.Objectif

Reprenons le fichier XML sur lequel nous avons travaillé.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE annuaire SYSTEM "annuaire.dtd">
<annuaire>
    <personne type="étudiant">
        <nom>HEUTE</nom>
        <prenom>Thomas</prenom>
        <email>webmaster@xmlfacile.com</email>
    </personne>
    <personne type="chanteur">
        <nom>SOUCHON</nom>
        <prenom>Alain</prenom>
        <email>alain@souchon.name</email>
    </personne>
</annuaire>


Nous aimerions transformer ce fichier XML en fichier HTML suivant:
Qui a le code source suivant:

<html>
  <head>
    <title>Annuaire</title>
  </head>
  <body>
    <table border="1">
      <tr><th>Nom</th><th>Prenom</th><th>email</th></tr>
      <tr><td>HEUTE</td><td>Thomas</td><td>webmaster@xmlfacile.com</td></tr>
      <tr><td>SOUCHON</td><td>Alain</td><td>alain@souchon.name</td></tr>
    </table>
  </body>
</html>


Je vous assure que cela va être facile.

3.La transformation XSL

Voici la première étape.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="ISO-8859-1" indent="yes"/>
    <xsl:template match="/">
        <html>
            <head><title>Annuaire</title></head>
            <body>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>


En appliquant cette feuille de style(Cf. section "installation") sur n'importe quel fichier XML on aura:
<html>
    <head><title>Annuaire</title></head>
    <body>
    </body>
</html>
  • A la première ligne, on précise la version d'XML que l'on utilise, (n'oublions pas qu'un fichier XSL est un fichier XML [c'est quoi?) ainsi que l'encodage [c'est quoi?(ici l'encodage europe de l'ouest)
  • Ensuite on trouve ce qui différencie un fichier XSL d'un fichier XML. La racine du fichier est imposée, elle doit être <xsl:stylesheet> (ou son alias <xsl:transform>) et doit préciser la version d'XSLT utilisée.
  • On définit le type de fichier de sortie dont 3 sont reconnus: text, xml ou html. Ici on a bien entendu choisit HTML. On a également défini l'encodage.
  • <xsl:template match="/"> est évoqué dès que la racine du fichier XML à transformer est rencontrée. Dans le cas présent dès que la racine est affichée le parseur écrit le contenu de la balise <xsl:template/>
Sur cet exemple, on ne le voit pas très bien mais un fichier XSL n'est pas comme un programme ordinaire, il ne se lit pas nécessairement de haut en bas. Tout dépend du contenu de votre fichier XML.

4.Tranformation XSL (apply-templates)

Après la première, la deuxième étape.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="ISO-8859-1"/>
    <xsl:template match="/">
        <html>
            <head><title>Annuaire</title></head>
            <body>
                <xsl:apply-templates select="annuaire"/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="annuaire">
        <table border="1">
            <tr><th>Nom</th><th>Prenom</th><th>email</th></tr>
            <xsl:apply-templates select="personne"/>
        </table>
    </xsl:template>

    <xsl:template match="personne">
    </xsl:template>
</xsl:stylesheet>
  • On a rajouté la balise <xsl:apply-templates> au milieu des balises body pour indiquer au parser qu'à cet endroit on souhaite appliquer les transformations de la balise annuaire.
  • La balise annuaire est très similaire à la précédente, on décrit le début du tableau, on demande la transformation des balises personne puis on décrit la fin du tableau.
  • La balise personne est très simple pour le moment.
Il est temps maintenant de passer à l'ultime étape.

5.Transformation XSL (value-of)

On se rapproche de la fin, maintenant il va falloir afficher le contenu d'une balise XML.



  • Pour chacune des personnes on veut une nouvelle ligne c'est pourquoi la balise <xsl:apply-templates> est entre les balises <tr>
  • Il n'y a pas d'attribut select car on veut appliquer toutes les transformations. En fait on pouvait déjà le faire pour les autres balises.
  • Pour chacune des balises nom, prenom et email on veut que le contenu soit entre les balises HTML <td>. On utilise la balise XSL <xsl:value-of>pour afficher la valeur de nom, prenom ou email
Maintenant nous allons voir un fichier différent qui arrive à un résultat identique.

6.Autre manière de faire

Cette version plus courte fonctionne également.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="ISO-8859-1"/>
    <xsl:template match="/">
        <html>
            <head><title>Annuaire</title></head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="annuaire">
        <table border="1">
            <tr><th>Nom</th><th>Prenom</th><th>email</th></tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="personne">
        <tr>
            <td><xsl:value-of select="nom"/></td>
            <td><xsl:value-of select="prenom"/></td>
            <td><xsl:value-of select="email"/></td>
        </tr>
    </xsl:template>
</xsl:stylesheet>

  • Ici on a supprimé les attributs 'select' des balises xsl:apply-templates
  • On a aussi supprimé les balises <xsl:template match="prenom">,<xsl:template match="nom"> et <xsl:template match="email">
On peut aussi remarquer que dans ce cas on est libre de les mettre dans l'ordre que l'on veut. L'attribut 'select' fonctionne un peu comme les arborescences des répertoires. On peut aussi récupérer une balise en remontant dans l'arborescence.
Juste une petite modification dans la balise personne pour montrer comment on récupère un attribut.


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="ISO-8859-1"/>
    <xsl:template match="/">
        <html>
            <head><title>Annuaire</title></head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="annuaire">
        <table border="1">
            <tr><th>Nom</th><th>Prenom</th><th>email</th></tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="personne">
        <tr><td><xsl:value-of select="@type"/>: <xsl:value-of select="nom"/></td>
            <td><xsl:value-of select="prenom"/></td>
            <td><xsl:value-of select="email"/></td></tr>
    </xsl:template>
</xsl:stylesheet>
  • On met un @ devant les attributs pour les récupérer.
Et si on avait voulu récupérer l'attribut toto de la balise annuaire dans la balise personne, on aurait mis './../@toto' dans l'attribut select. C'est en fait le langage XPath qui est utilisé.

7.Conclusion

Ce n'est qu'un aperçu de ce que l'on peut faire avec XSLT mais rien qu'avec ceci vous pouvez déjà vous amuser. J'espère que cela vous suffit pour mesurer l'intérêt qu'apportent de telles feuilles de style.

dimanche 21 octobre 2012

Surdéfinition d’opérateurs C++


Comment ça marche

Nous avons commencé à réaliser une classe Point qui permet la recopie d’objet. Mais jusqu’à maintenant, nous avons été obligés de créer des méthodes telles que "Coincide" qui vérifie que deux points sont égaux. Nous aurions pu également réaliser une fonction membre qui ajoute un point à un autre :
class Point
{
     int x;
     int y;
public :
     Point();
     Point(int a, int b);
     Point(const Point & pt);
     void Ajoute(const Point & pt);
     ... // D’éventuelles autres méthodes 
};
Vous sentez alors qu’il serait très appréciable et plus naturel de pouvoir faire quelque chose comme :
     Point a(1,2);
     Point b(3,4);
     Point c;
     c = a + b;
C++ permet de réaliser une surdéfinition des opérateurs de base, comme "+", "-", "*", "/", "&", "^", etc. La liberté étant totale, vous pouvez faire réellement ce que vous voulez, par exemple une soustraction pour l’opérateur d’addition et inversement. Mais il est clair qu’il est plus que conseillé de respecter la signification de chacun de ces opérateurs.

Opérateurs simples

Mettre en oeuvre les opérateurs simples est une opération assez rapide. Un exemple est utile pour vous montrer comment on fait :
class Point
{
     int x;
     int y;
public :
     Point();
     Point(int a, int b);
     Point(const Point & pt);
     Point operator+(const Point & a)
     {
          Point p;
          p.x = a.x + x;
          p.y = a.y + y;
        return p;
     }
     ... // D’éventuelles autres méthodes 
};
Des explications sont nécessaires. Tout d’abord, vous remarquerez le "const Point & a". Ceci signifie que l’on passe un point en paramètre (l’autre point de l’addition est en fait la classe appelante elle-même). Ce dernier est transmis par référence, afin d’éviter une recopie, lourde et moins rapide. Le "const" est optionnel mais permet d’éviter de modifier les paramètres et également autorise l’utilisation d’objets constants.
L’opérateur rend un Point. En fait, on rend en fin de méthode le point qui a été créé temporairement au départ et qui contient la somme des deux paramètres. Plus exactement, on rend une copie de cet objet, le retour de la fonction étant "Point", et non "Point&" ou "Point*". Ceci est normal. Il faut savoir que l’objet créé dans la méthode sera automatiquement détruit à la fin de cette dernière. On ne peut bien évidemment pas rendre l’adresse d’un objet qui sera détruit ! D’où la nécessité d’une recopie.
Ce que nous avons mis en oeuvre pour l’opérateur d’addition, nous pouvons en faire de même pour tous les autres opérateurs "simples". Quelques exemples :
class Point
{
 int x;
 int y;
public :
 Point(){}
 Point(int a, int b){ x=a; y=b; }
 Point operator +(const Point & a);
 Point operator -(const Point & a);
 int operator==(const Point & p);
 void Affiche()
 {
  // "this" est un pointeur sur la classe même 
  cout << this << "->" << x << ", " << y << endl;
 }
};
Point Point::operator +(const Point & a)
// Addition de 2 points 
 Point p;
 p.x = x + a.x;
 p.y = y + a.y;
 return p;
}
Point Point::operator -(const Point & a)
// Soustraction de 2 points 
 Point p;
 p.x = x - a.x;
 p.y = y - a.y;
 return p;
}
int Point::operator==(const Point & p)
// Egalité de 2 points (remplace "Coincide") 
 if( x==p.x && y==p.y )
  return 1;
 else
  return 0;
}
void main()
{
 Point p(1,2);
 p.Affiche();
 Point pp(3,4);
 pp.Affiche();
 Point ppp = p+pp;
 ppp.Affiche();
 if( p==pp )
  cout << "p==pp" << endl;
 else
  cout << "p!=pp" << endl;
 p = ppp;
 p.Affiche();
 pp = p-ppp;
 pp.Affiche();
 if( p==ppp )
  cout << "p==ppp" << endl;
 else
  cout << "p!=ppp" << endl;
}

Opérateur d’affectation

L’opérateur d’affectation "=" représente un cas particulier. En effet, nous retrouvons le même problème que lors de la construction par recopie : il est toujours possible d’effectuer une affectation entre deux objets (de même type), mais que se passe-t-il s’ils contiennent des pointeurs (cf. problématique de recopie) ! C’est pourquoi il est souvent important d’implémenter ce type d’opérateur.
Il n’est pas plus difficile à mettre en oeuvre :
#include <iostream.h>
class Vecteur
{
 int *pVecteur;
 int nTaille;
public :
 Vecteur(int);
 Vecteur(const Vecteur &);
 ~Vecteur();
 int GetAt(int ind)
 {
  if( ind>=0 && ind<nTaille )
   return pVecteur[ind];
  else
   return 0;
 }
 void SetAt(int ind, int val)
 {
  if( ind>=0 && ind<nTaille )
   pVecteur[ind]=val;
 }
 int Size(){ return nTaille; }
 Vecteur& operator =(const Vecteur & v);
};
Vecteur::Vecteur(int Taille)
{
 nTaille = Taille;
 pVecteur = new int[nTaille];
}
Vecteur::Vecteur(const Vecteur & v)
{
 nTaille = v.nTaille;
 pVecteur = new int[nTaille];
 forint i=0; i<nTaille; i++ )
  pVecteur[i]=v.pVecteur[i];
}
Vecteur::~Vecteur()
{
 delete []pVecteur;
}
Vecteur& Vecteur::operator =(const Vecteur & v)
{
 // On vérifie que les objets ne sont pas les mêmes ! 
 if( this != &v )
 {
  delete []pVecteur; // Effacement du vecteur 
  nTaille = v.nTaille;
  pVecteur = new int[nTaille]; // Allocation 
  // Recopie des valeurs 
  forint i=0; i<nTaille; i++ )
   pVecteur[i]=v.pVecteur[i];
 }
 return *this;
}
void main()
{
 Vecteur *v;
 v = new Vecteur(10);
 forint i=0; i<v->Size(); i++ )
  v->SetAt(i, i*i-i);
 Vecteur vv(5);
 vv = *v;
 vv.SetAt(0, 13);
 vv.SetAt(1, 13);
 vv.SetAt(2, 13);
 for( i=0; i<v->Size(); i++ )
  cout << v->GetAt(i) << " ";
 cout << endl;
 for( i=0; i<vv.Size(); i++ )
  cout << vv.GetAt(i) << " ";
 cout << endl;
 delete v;
}
Cette fois-ci, nous rendons par contre une référence sur l’objet, car nous devons rendre la classe elle-même et non une copie, comme vous pouvez le comprendre.

samedi 20 octobre 2012

Exercice préliminaire C++


Vous avez appris très rapidement les "bases" du C++ dans les précédents chapitres. Il est évident que vous n’avez pas encore pu assimiler toutes ces notions. Pour ce faire, rien n’est plus efficace qu’une mise en application.
L’exercice qui vous est proposé, a pour objet la réalisation d’un ensemble de deux classes, qui s’occupent de la gestion de chaînes de caractères formatées (mise en italique, gras et couleur).
La première classe gère la première partie, à savoir la chaîne de caractères. En voici sa description rapide :

  • gestion d’une chaîne de caractères et de sa taille,
  • constructeur par défaut,
  • constructeur initialisant à partir d’une chaîne de caractères (char*),
  • constructeur par recopie,
  • destructeur,
  • surcharge de l’opérateur = (affectation de chaîne),
  • surcharge de l’opérateur == (égalité de chaîne),
  • surcharge de l’opérateur += (trois différents, un qui gère un String, un autre un char* et un dernier un char),
  • surcharge de l’opérateur + (concaténation),
  • surcharge de l’opérateur [] (accès à un caractère de la chaîne stockée),
  • vérification de l’initialisation de la classe (on vérifie que la chaîne n’est pas vide),
  • mise à zéro des paramètres (chaîne vide),
  • renvoie de la taille de la chaîne,
  • et affichage de la chaîne.

Vous êtes bien entendu libre de rajouter d’autres méthodes.
La deuxième classe hérite de la première, et rajoute une couche gérant le formatage du texte. Description sommaire :

  • gestion du formatage : Italic, Bold et Couleur (un short pour faire simple),
  • constructeur par défaut,
  • constructeur connaissant une chaîne de caractères et éventuellement les options de formatage,
  • constructeur connaissant une chaîne de caractères de type String et éventuellement les options de formatage,
  • constructeur connaissant les options de formatage,
  • constructeur par recopie,
  • destructeur (optionnel),
  • surcharge de l’opérateur = (affectation) pour le cas d’une copie de chaîne formatée,
  • surcharge de l’opérateur = (affectation) pour le cas d’une copie de chaîne non formatée (classe de base),
  • méthodes permet la gestion de l’italique (mise en "italic" et renvoi d’information),
  • méthodes permet la gestion de Bold (mise en "Bold" et renvoi d’information),
  • Colorisation et renvoie de couleur,
  • Affichage de la chaîne et des informations de formatage, en utilisation la notation HTML, à savoir :<i> pour la mise en italique et </i> à la fin,
  • <b> pour la mise en gras et </b> à la fin,
  • <font color="#RVB"> pour la couleur et </font> à la fin.

La réalisation de ces classes est assez simple si vous procédez par étape. Utilisez également très allègrement les exemples fournis auparavant. N’hésitez pas à regarder comment on déclare un constructeur par recopie, etc.
C’est également le moment pour voir de plus près comment fonctionne le debugger, car vous ne serez pas sans faire quelques erreurs... de frappe !
Bon courage !


Solution

// chaine.h    : Interface de la classe String
///////////////////////////////////////////////////////////////////////////////////////////
//
// Auteur :    Gwenaël Brunet    E-Mail : Gwenael.Brunet@enst-bretagne.fr
// --------    Dpt iTi - LATIM
//        ENST Bretagne    Tél. : 02.98.00.10.61
//        BP 832        Fax  : 02.98.00.10.98
//        29285 BREST Cedex
//
///////////////////////////////////////////////////////////////////////////////////////////
//
// Classe String :
// ---------------
// Description :    Interface de la classe String
// Utilisation :    Gestion des chaînes de caractères, au sens large, c'est-à-dire qu'il\
//        n'y a pas de distinction faite entre un mot, une ligne, etc..
//
// Création    :    11/06/99
//
// Dernière
// Mise à jour :    14/06/99
//
/////[ INFORMATIONS ]//////////////////////////////////////////////////////////////////////
// 
// Cette classe sert d'illustration, d'exemple, au tutorial de C++ suivant :

// 

// http://www-iti.enst-bretagne.fr/~brunet/MesCours/Tutorial_C++/

// 

// Elle n'a donc aucune autre utilité que la pédagogie...
//
///////////////////////////////////////////////////////////////////////////////////////////
#ifndef _CLASS_STRING
#define _CLASS_STRING

// Quelques "define" utiles.
#define UINT unsigned int
#define NULL 0

class String
{
protected :
    char *m_strString;    // la chaîne en elle-même
    UINT m_uiSize;        // la longueur de la chaîne

public :
    String( );
    String( char* );
    String( const String & );
    ~String( );

    String & operator=( const String & );
    bool operator==( const String & );

    String& operator+=( const String & );
    String& operator+=( const char* );
    String& operator+=( const char );
    String operator+( const String & );

    char & operator[](UINT);

    bool IsEmpty();
    void Empty();
    UINT GetSize(){ return m_uiSize; }

    virtual void Display(bool bEnter=true);
};

#endif // _CLASS_STRING


// chaine.cpp    : Implémentation de la classe String
///////////////////////////////////////////////////////////////////////////////////////////
//
// Auteur :    Gwenaël Brunet    E-Mail : Gwenael.Brunet@enst-bretagne.fr
// --------    Dpt iTi - LATIM
//        ENST Bretagne    Tél. : 02.98.00.10.61
//        BP 832        Fax  : 02.98.00.10.98
//        29285 BREST Cedex
//
///////////////////////////////////////////////////////////////////////////////////////////
//
// Classe String :
// ---------------
// Description :    Implémentation de la classe String
// Utilisation :    Gestion des chaînes de caractères, au sens large, c'est-à-dire qu'il\
//        n'y a pas de distinction faite entre un mot, une ligne, etc..
//
// Création    :    11/06/99
//
// Dernière
// Mise à jour :    14/06/99
//
/////[ INFORMATIONS ]//////////////////////////////////////////////////////////////////////
// 
// Cette classe sert d'illustration, d'exemple, au tutorial de C++ suivant :

// 

// http://www-iti.enst-bretagne.fr/~brunet/MesCours/Tutorial_C++/

// 

// Elle n'a donc aucune autre utilité que la pédagogie...
//
///////////////////////////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include "chaine.h"


///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 15:33:05] 
//  Class   : String 
//  Function: String 
// 
//  Description: Constructeur par défaut de String -> initialisation à "0" 
// 
//  Parameters: None 
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
String::String( )
{
    m_uiSize = 0;
    m_strString = NULL;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 15:57:19] 
//  Class   : String 
//  Function: String 
// 
//  Description: Constructeur initialisant par chaîne 
// 
//  Parameters: 
//    char *string -  La chaîne d'initialisation (recopiée)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
String::String( char *string )
{
    m_strString = string;
    m_uiSize = 0;

    // Mesure de la chaîne
    while( m_strString[m_uiSize]!='\0' )
        m_uiSize++;

    m_strString = new char[m_uiSize];    // Allocation mémoire
    for( UINT i=0; i<m_uiSize; i++ )
        // Recopie
        m_strString[i] = string[i];
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 15:59:13] 
//  Class   : String 
//  Function: String 
// 
//  Description: Constructeur par recopie 
// 
//  Parameters: 
//    const String &string -  chaîne à recopier
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
String::String( const String &string )
{
    m_uiSize = string.m_uiSize;
    m_strString = new char[m_uiSize];

    for( UINT i=0; i<m_uiSize; i++ )
        // Recopie
        m_strString[i] = string.m_strString[i];
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:00:06] 
//  Class   : String 
//  Function: ~String 
// 
//  Description: Destructeur 
// 
//  Parameters: None 
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
String::~String( )
{
    Empty();
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:08:19] 
//  Class   : String 
//  Function: operator= 
// 
//  Description: Surcharge de l'opérateur d'affectation 
// 
//  Parameters: 
//    const String &string -  la chaîne à copier
//  Return: String & -  *this
// 
///////////////////////////////////////////////////////////////////////////////
String & String::operator=( const String &string )
{
    if( this!= &string )
    {
        if( m_strString )
            delete m_strString;

        m_uiSize = string.m_uiSize;
        m_strString = new char[m_uiSize];

        for( UINT i=0; i<m_uiSize; i++ )
            // Recopie
            m_strString[i] = string.m_strString[i];
    }

    return *this;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:10:30] 
//  Class   : String 
//  Function: operator== 
// 
//  Description: Surcharge de l'opérateur d'égalité 
// 
//  Parameters: 
//    const String &string -  la chaîne à comparer
//  Return: bool -  le résultat de la comparaison
// 
///////////////////////////////////////////////////////////////////////////////
bool String::operator==( const String &string )
{
    // UPDATE : merci Stéphane !
    if( m_uiSize!=string.m_uiSize )
        return false;
    // ----------------------------

    for( UINT i=0; i<m_uiSize; i++ )
        if( m_strString[i]!=string.m_strString[i] ) return false;
    return true;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:50:02] 
//  Class   : String 
//  Function: operator+ 
// 
//  Description: Surcharge de l'opérateur d'addition 
// 
//  Parameters: 
//    const String &string -  La chaîne à concaténer
//  Return: String -  la chaîne de retour
// 
///////////////////////////////////////////////////////////////////////////////
String String::operator+( const String &string )
{
    String buffer; // variable temporaire de retour

    buffer.m_uiSize = m_uiSize + string.m_uiSize;
    buffer.m_strString = new char[buffer.m_uiSize];

    // Recopie
    for( UINT i=0; i<m_uiSize; i++ )
        buffer.m_strString[i] = m_strString[i];
    for( i=0; i<string.m_uiSize; i++ )
        buffer.m_strString[i+m_uiSize] = string.m_strString[i];

    return buffer;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 10:10:47] 
//  Class   : String 
//  Function: operator+= 
// 
//  Description: Surcharge de l'opérateur += -> concaténation 
// 
//  Parameters: 
//    const String &string -  la chaîne de type String à ajouter
//  Return: String& -  La chaîne en retour
// 
///////////////////////////////////////////////////////////////////////////////
String& String::operator+=( const String &string )
{
    UINT NewSize = string.m_uiSize + m_uiSize;
    char *buffer = new char[NewSize];

    for( UINT i=0; i<m_uiSize; i++ )
        buffer[i] = m_strString[i];
    for( i=0; i<string.m_uiSize; i++ )
        buffer[i+m_uiSize] = string.m_strString[i];

    delete m_strString;
    m_strString = buffer;
    m_uiSize = NewSize;

    return *this;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 10:15:01] 
//  Class   : String 
//  Function: operator+= 
// 
//  Description: Surcharge de l'opérateur += -> concaténation 
// 
//  Parameters: 
//    const char string -  la chaîne de type char* à ajouter
//  Return: String& -  La chaîne en retour
// 
///////////////////////////////////////////////////////////////////////////////
String& String::operator+=( const char *string )
{
    UINT size=0;
    while( string[size]!='\0' )
        size++;

    char *buffer = new char[size+m_uiSize];

    for( UINT i=0; i<m_uiSize; i++ )
        buffer[i] = m_strString[i];
    for( i=0; i<size; i++ )
        buffer[i+m_uiSize] = string[i];

    delete m_strString;
    m_strString = buffer;
    m_uiSize+=size;

    return *this;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 10:18:49] 
//  Class   : String 
//  Function: operator+= 
// 
//  Description: Concaténation d'un caractère 
// 
//  Parameters: 
//    const char c -  Le caractère
//  Return: String& -  La chaîne en retour
// 
///////////////////////////////////////////////////////////////////////////////
String& String::operator+=( const char c )
{
    m_uiSize++;

    char *buffer = new char[m_uiSize];

    for( UINT i=0; i<m_uiSize; i++ )
        buffer[i] = m_strString[i];
    buffer[m_uiSize-1] = c;

    delete m_strString;
    m_strString = buffer;

    return *this;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:51:01] 
//  Class   : String 
//  Function: operator[] 
// 
//  Description: Accès à un caractère 
// 
//  Parameters: 
//    int nIndice -  l'indice du caractère
//  Return: char & -  le caractère
// 
///////////////////////////////////////////////////////////////////////////////
char & String::operator[](UINT nIndice)
{
    if( nIndice<0 || nIndice>=m_uiSize )
        return m_strString[0];

    return m_strString[nIndice];
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 16:57:02] 
//  Class   : String 
//  Function: IsEmpty 
// 
//  Description: Indique si la chaîne est vide 
// 
//  Parameters: None 
//  Return: bool -  true si la chaîne est vide
// 
///////////////////////////////////////////////////////////////////////////////
bool String::IsEmpty()
{
    if( m_uiSize==0 )
        return true;

    return false;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 17:01:13] 
//  Class   : String 
//  Function: Empty 
// 
//  Description: Efface la chaîne 
// 
//  Parameters: None 
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void String::Empty()
{
    if( m_strString )
    {
        delete m_strString;
        m_strString = NULL;
    }
    m_uiSize = 0;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [11/06/99 17:00:49] 
//  Class   : String 
//  Function: Display 
// 
//  Description: Ecrit la chaîne 
// 
//  Parameters: 
//    bool bEnter -  true (défaut) si on veut faire un retour à la fin
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void String::Display( bool bEnter )
{
    for( UINT i=0; i<m_uiSize; i++ )
        cout << m_strString[i];
    if( bEnter )
        cout << endl;
}
// FormatedString.h    : Interface de la classe FormatedString
///////////////////////////////////////////////////////////////////////////////////////////
//
// Auteur :    Gwenaël Brunet    E-Mail : Gwenael.Brunet@enst-bretagne.fr
// --------    Dpt iTi - LATIM
//        ENST Bretagne    Tél. : 02.98.00.10.61
//        BP 832        Fax  : 02.98.00.10.98
//        29285 BREST Cedex
//
///////////////////////////////////////////////////////////////////////////////////////////
//
// Classe FormatedString :
// -----------------------
// Description :    Interface de la classe FormatedString
// Utilisation :    Gestion des chaînes de caractères formatée : hérite de la classe\
//        String, et lui rajoute des notions de formatage de texte, italic,\
//        gras et couleur.
//
// Création :    12/06/99
//
// Dernière
// Mise à jour :    14/06/99
//
/////[ INFORMATIONS ]//////////////////////////////////////////////////////////////////////
// 
// Cette classe sert d'illustration, d'exemple, au tutorial de C++ suivant :

// 

// http://www-iti.enst-bretagne.fr/~brunet/MesCours/Tutorial_C++/

// 

// Elle n'a donc aucune autre utilité que la pédagogie...
//
///////////////////////////////////////////////////////////////////////////////////////////
#ifndef _CLASS_FORMATEDSTRING
#define _CLASS_FORMATEDSTRING

#include "chaine.h"

#define DEFAULT_FORMATEDSTRING_COLOR 0

class FormatedString : public String
{
    bool m_bItalic;
    bool m_bBold;
    short m_sColor;

    // Initialisation interne
    inline void InitFormat( bool bItal=0, bool bBold=0, short Color=DEFAULT_FORMATEDSTRING_COLOR );

public :
    // Constructeurs / destructeur
    FormatedString( );
    FormatedString( char* str, bool bItal=0, bool bBold=0, short Color=DEFAULT_FORMATEDSTRING_COLOR );
    FormatedString( const String & str, bool bItal=0, bool bBold=0, short Color=DEFAULT_FORMATEDSTRING_COLOR );
    FormatedString( bool bItal, bool bBold, short Color=DEFAULT_FORMATEDSTRING_COLOR );
    FormatedString( const FormatedString & fstr);
    ~FormatedString( );

    // Surcharge opérateurs
    FormatedString & operator=( FormatedString & fstr);
    FormatedString & operator=( String & str);

    // Accès aux variables de formatage
    void MakeItalic( bool bItal=true );
    bool IsItalic( );

    void MakeBold( bool bBold=true );
    bool IsBold( );

    void Colorize( short sColor );
    short GetColor( );

    void Display( bool bReturn=true );
};

#endif // _CLASS_FORMATEDSTRING
// FormatedString.cpp    : Implémentation de la classe FormatedString
///////////////////////////////////////////////////////////////////////////////////////////
//
// Auteur :    Gwenaël Brunet    E-Mail : Gwenael.Brunet@enst-bretagne.fr
// --------    Dpt iTi - LATIM
//        ENST Bretagne    Tél. : 02.98.00.10.61
//        BP 832        Fax  : 02.98.00.10.98
//        29285 BREST Cedex
//
///////////////////////////////////////////////////////////////////////////////////////////
//
// Classe FormatedString :
// -----------------------
// Description :    Implémentation de la classe FormatedString
// Utilisation :    Gestion des chaînes de caractères formatée : hérite de la classe\
//        String, et lui rajoute des notions de formatage de texte, italic,\
//        gras et couleur.
//
// Création    :    12/06/99
//
// Dernière
// Mise à jour :    14/06/99
//
/////[ INFORMATIONS ]//////////////////////////////////////////////////////////////////////
// 
// Cette classe sert d'illustration, d'exemple, au tutorial de C++ suivant :

// 

// http://www-iti.enst-bretagne.fr/~brunet/MesCours/Tutorial_C++/

// 

// Elle n'a donc aucune autre utilité que la pédagogie...
//
///////////////////////////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include "FormatedString.h"


///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 12:42:40] 
//  Class   : FormatedString 
//  Function: FormatedString 
// 
//  Description: Constructeur par défaut de la classe FormatedString 
// 
//  Parameters: None 
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::FormatedString( ) : String( )
{
    InitFormat(  );
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 12:43:24] 
//  Class   : FormatedString 
//  Function: FormatedString 
// 
//  Description: Constructeur initialisant de la classe FormatedString,\ 
//        connaissant une chaîne de caractères 
// 
//  Parameters: 
//    char* str -  La chaîne de caractères
//    bool bItal -  Italic false/true
//    bool bBold -  Bold false/true
//    short Color -  Couleur (0)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::FormatedString( char* str, bool bItal, bool bBold, short Color ) : String( str )
{
    InitFormat( bItal, bBold, Color );
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 12:45:36] 
//  Class   : FormatedString 
//  Function: FormatedString 
// 
//  Description: Constructeur initialisant de la classe FormatedString, \ 
//                 connaissant un String 
// 
//  Parameters: 
//    const String & str -  La chaîne
//    bool bItal -  Italic false/true
//    bool bBold -  Bold false/true
//    short Color -  Couleur (0)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::FormatedString( const String & str, bool bItal, bool bBold, short Color ) : String( str )
{
    InitFormat( bItal, bBold, Color );
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 12:46:31] 
//  Class   : FormatedString 
//  Function: FormatedString 
// 
//  Description: Constructeur initialisant de la classe FormatedString, \ 
//connaissant le formatage 
// 
//  Parameters: 
//    bool bItal -  Italic false/true
//    bool bBold -  Bold false/true
//    short Color -  Couleur (0)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::FormatedString( bool bItal, bool bBold, short Color ) : String( )
{
    InitFormat( bItal, bBold, Color );
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 12:47:36] 
//  Class   : FormatedString 
//  Function: FormatedString 
// 
//  Description: Constructeur par recopie 
// 
//  Parameters: 
//    const FormatedString & fstr -  la variable à recopier
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::FormatedString( const FormatedString & fstr) : String( (String)fstr )
{
    InitFormat( fstr.m_bItalic, fstr.m_bBold, fstr.m_sColor );
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:02:00] 
//  Class   : FormatedString 
//  Function: ~FormatedString 
// 
//  Description: Destructeur 
// 
//  Parameters: None 
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString::~FormatedString( )
{
    // Nothing to do
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:03:14] 
//  Class   : FormatedString 
//  Function: InitFormat 
// 
//  Description: Initialisation des membres privés 
// 
//  Parameters: 
//    bool bItal -  Italic false/true
//    bool bBold -  Bold false/true
//    short Color -  Couleur (0)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void FormatedString::InitFormat( bool bItal, bool bBold, short Color )
{
    m_bItalic    = bItal;
    m_bBold        = bBold;
    m_sColor    = Color;
}


///////////////////////////////////////////////////////////////////////////////
//// Surcharge opérateurs 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:15:04] 
//  Class   : FormatedString 
//  Function: operator= 
// 
//  Description: Surcharge opérateur = 
// 
//  Parameters: 
//    FormatedString & fstr -  l'objet à recopier de type FormatedString
//  Return: FormatedString & -  *this
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString & FormatedString::operator=( FormatedString & fstr)
{
    String *strThis, *strParam;

    strThis = this;
    strParam = &fstr;

    *strThis = *strParam;
    InitFormat( fstr.m_bItalic, fstr.m_bBold, fstr.m_sColor );

    return *this;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:15:53] 
//  Class   : FormatedString 
//  Function: operator= 
// 
//  Description: Surcharge opérateur = 
// 
//  Parameters: 
//    String & str -  l'objet à recopier de type
//  Return: FormatedString & -  *this
// 
///////////////////////////////////////////////////////////////////////////////
FormatedString & FormatedString::operator=( String & str )
{
    String *strThis;
    strThis = this;

    *strThis = str;
    InitFormat(  );

    return *this;
}


///////////////////////////////////////////////////////////////////////////////
//// Accès aux variables de formatage 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:18:09] 
//  Class   : FormatedString 
//  Function: MakeItalic 
// 
//  Description: Active/désactive l'italic d'une chaîne 
// 
//  Parameters: 
//    bool bItal -  True pour italic, false sinon.
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void FormatedString::MakeItalic( bool bItal )
{
    m_bItalic = bItal;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:18:50] 
//  Class   : FormatedString 
//  Function: IsItalic 
// 
//  Description: Indique si la chaîne est italique ou non
// 
//  Parameters: None 
//  Return: bool -  True si la chaîne est italique
// 
///////////////////////////////////////////////////////////////////////////////
bool FormatedString::IsItalic( )
{
    return m_bItalic;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:19:34] 
//  Class   : FormatedString 
//  Function: MakeBold 
// 
//  Description: Active/désactive le bold d'une chaîne 
// 
//  Parameters: 
//    bool bBold -  True pour Bold, false sinon
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void FormatedString::MakeBold( bool bBold )
{
    m_bBold = bBold;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:20:39] 
//  Class   : FormatedString 
//  Function: IsBold 
// 
//  Description: Indique si la chaîne est bold ou non 
// 
//  Parameters: None 
//  Return: bool -  True si Bold
// 
///////////////////////////////////////////////////////////////////////////////
bool FormatedString::IsBold( )
{
    return m_bBold;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:21:24] 
//  Class   : FormatedString 
//  Function: Colorize 
// 
//  Description: Initialise la couleur de la chaîne 
// 
//  Parameters: 
//    short Color -  la couleur
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void FormatedString::Colorize( short Color )
{
    m_sColor = Color;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:21:40] 
//  Class   : FormatedString 
//  Function: GetColor 
// 
//  Description: Renvoie la couleur actuelle de la chaîne 
// 
//  Parameters: None 
//  Return: short -  La couleur actuelle
// 
///////////////////////////////////////////////////////////////////////////////
short FormatedString::GetColor( )
{
    return m_sColor;
}

///////////////////////////////////////////////////////////////////////////////
// 
//  Author  : [Gwenaël Brunet], Created : [14/06/99 13:23:04] 
//  Class   : FormatedString 
//  Function: Display 
// 
//  Description: Affichage de la chaîne formatée (le formatage est signalé \ 
//                 en utilisant les symboles HTML) 
// 
//  Parameters: 
//    bool bReturn -  Permet de choisir si on veut faire un retour chariot\
//                        à la fin de la ligne (true par défaut)
//  Return: None 
// 
///////////////////////////////////////////////////////////////////////////////
void FormatedString::Display( bool bReturn )
{
    // Formatage début
    if( m_bItalic ) cout << "<i>";
    if( m_bBold ) cout << "<b>";
    if( m_sColor ) cout << "<font color=\"#" << m_sColor << "\">";

    // Affichage de la chaîne
    String::Display( false );

    // Formatage fin
    if( m_sColor ) cout << "</font>";
    if( m_bBold ) cout << "</b>";
    if( m_bItalic ) cout << "</i>";

    if( bReturn ) cout << endl;    // Return si nécessaire
}