Affichage des articles dont le libellé est C. Afficher tous les articles
Affichage des articles dont le libellé est C. Afficher tous les articles

samedi 27 octobre 2012

Présentation Générale C++


Généralités

Puisque cela n’est pas foncièrement utile, je vous fais grâce de l’historique du langage C++. Vous devez juste savoir, éventuellement, qu’il a été conçu par Bjarne Stroustrup, ce qui aide pour trouver l’excellente bible du C++, écrite par lui-même[1].
Pour commencer cette présentation, parlons de quelques généralités, et d’abord du pourquoi du C++.
C’est avant tout une nécessité de répondre à des besoins générés par de gros projets. Ils nécessitent une façon de travailler plus rigoureuse, pour un code plus structuré, extensible, réutilisable et enfin si possible, portable. Ceci est assez limité lorsque l’on emploie un langage simplement structuré tel que C ou Turbo Pascal.

Programmation Orientée Objet

La Programmation Orientée Objet (P.O.O.) est une solution. Elle permet d’introduire le concept d’objet justement, qui consiste en un ensemble de données et de procédures qui agissent sur ces données.
Lorsque l’objet est parfaitement bien écrit, il introduit la notion fondamentale d’Encapsulation des données. Ceci signifie qu’il n’est plus possible pour l’utilisateur de l’objet, d’accéder directement aux données : il doit passer par des méthodes spécifiques écrites par le concepteur de l’objet, et qui servent d’interface entre l’objet et ses utilisateurs. L’intérêt de cette technique est évident : l’utilisateur ne peut pas intervenir directement sur l’objet, ce qui diminue les risques d’erreur, ce dernier devenant une "boîte noire".
Une autre notion importante en P.O.O. est l’héritage. Elle permet la définition d’une nouvelle classe à partir d’une classe existante. Il est alors possible de lui adjoindre de nouvelles données, de nouvelles fonctions membres (procédures) pour la spécialiser.

Différences entre C et C++

Nous allons parler ici d’un certain nombre de différences existant entre le C et le C++. Nous pourrions d’ailleurs plutôt utiliser le terme d’incompatibilités.

Les fonctions

Les fonctions en C peuvent être définies suivant deux modèles :

int CalculeSomme ( a, b )
int a; 
int b; 
{ 
     ... /* Fonction */ 
}    
int CalculeSomme ( int a, int b ) 
{ 
     ... /* Fonction */ 
}
Il faut simplement savoir que le C++ n’accepte que la seconde méthode.

Const

Le C++ a quelque peu modifié l’utilisation "C" de ce qualificatif. Pour rappel, "const" est utilisé pour définir une variable constante. C’est une bonne alternative à un define.
La portée en C++ est désormais plus locale. En C, un const permettait pour une variable globale d’être "visible" partout. C++ limite quant à lui la portée d’une telle variable, au fichier source contenant la déclaration.

Compatibilité de pointeurs

En C ANSI, un "void*" est compatible avec tout autre type de pointeurs, et inversement.
Par exemple, ceci est légal en C :
/* C */
void * pQqch;    /* Pointeur générique */
int * pEntier;    /* Pointeur sur un entier */
pEntier = pQqch;
pQqch = pEntier; 
Ces affectations font intervenir des conversions implicites. En C++, seule la conversion int* --› void* est implicite. L’autre reste possible, mais nécessite ce que l’on nomme un "cast" :
// C++ 
void * pQqch;             // Pointeur générique 
int * pEntier;            // Pointeur sur un entier 
pEntier = (int*)pQqch;  // "cast" en entier

jeudi 25 octobre 2012

Les bases du C++


Les spécificités de C++

Le langage C++ a adopté un certain nombre de nouvelles spécificités qu’il faut connaître avant de se lancer dans la P.O.O. proprement dite.

Les commentaires

Les commentaires d’un code source peuvent désormais être indiqués de deux façons différentes :
/* Ceci est un commentaire typique venant du C */
int nEntier; // Et ceci est la seconde possibilité
Ces nouveaux commentaires sont utilisables uniquement dans le cas où tout le reste de la ligne est un commentaire.

Déclarations

mardi 23 octobre 2012

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 
};


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...

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];
 for( int 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 
  for( int i=0; i<nTaille; i++ )
   pVecteur[i]=v.pVecteur[i];
 }
 return *this;
}
void main()
{
 Vecteur *v;
 v = new Vecteur(10);
 for( int 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
}