Td corrigé Le langage C++ pdf

Le langage C++

Dans le reste du programme, il devient maintenant possible de définir une fonction increment() totalement indépendante à la classe Nombre et qui peut ...




part of the document



lasse ne sont accessibles que par les fonctions membres de la classe en question. Il est possible d'enfreindre cette règle en précisant qu'une fonction externe à la classe ou qu'une seconde classe est amie et a donc le droit d'accéder aux membres privés (private) ou protégés (protected). Cette infraction est permise dans un soucis d'efficacité.

Déclarer une fonction ou une classe comme amies s'effectue simplement avec le mot réservé "friend". Pour illustrer cette possibilité, déclarons une classe Nombre qui permet de manipuler un entier:

class Nombre {
friend class Point; //la classe Point peut accéder a _nbre
friend void increment(Nombre &);//la fonction externe increment aussi
public:
int getnbre(void); //methode de la classe private:
int _nbre;
};


Dans le reste du programme, il devient maintenant possible de définir une fonction increment() totalement indépendante à la classe Nombre et qui peut manipuler directement la donnée membre privée:

#include
using namespace std;

void increment (Nombre &n)
{
n._nbre++;
}

void main(void)
{
Nombre a;

increment(a);
}

3) Héritage simple.

3.1) Généralités.

L'héritage (appelé aussi dérivation) permet de créer une nouvelle classe à partir d'une classe déjà existante. Cette dernière est appelée classe de base ou super classe. La classe dérivée hérite de toutes les données et fonctions membres public ou protected de la classe de base. Les méthodes et données de la super classe peuvent ainsi être réutilisées dans la classe dérivée.

Indiquer qu'une classe est dérivée s'indique lors de la définition de celle-ci en spécifiant un mode de dérivation qui peut être public, protected ou private:

class Vehicule { //définition de la super classe
public:
//données et fonctions membres
private:
//données et fonctions membres
protected:
//données et fonctions membres
};

class Voiture: public Vehicule //héritage de la classe Vehicule avec mode
{ //de dérivation public
…
};
3.2) Les différents modes de dérivation.

Spécifier un mode de dérivation permet de préciser quelles sont les données et fonctions membres de la super classe qui restent accessibles dans la classe dérivée. Si aucun mode de dérivation n'est précisé, c'est le mode private qui est pris par défaut. Le tableau suivant retrace les différentes possibilités:

Mode de dérivationSignification
public
C'est le mode le plus couramment utilisé. Les membres publics et protégés de la classe de base restent respectivement publics et protégés dans la classe dérivée.
private
Les membres publics et privés de la classe de base deviennent des membres privés dans la classe dérivée. 
protected
Les membres publics et protégés de la classe de base deviennent des membres protégés de la classe dérivée. 


3.3) Surcharge des méthodes de la classe de base dans la classe dérivée.

Une méthode de la classe de base peut être surdéfinie dans la classe dérivée. Les 2 méthodes ont alors le même nom et la même signature. Pour les différencier, on précisera la fonction membre souhaitée grâce à l'opérateur de portée "::".


class Vehicule
{
public:
void affiche(void);

protected:
int poids;
};


class Voiture: public Vehicule
{
public:
void affiche(void);
void saisie(void);
};


void Voiture::affiche(void) //définition de la fonction //affiche() de Voiture
{
Vehicule::poids=600; //accès a la donnée poids de Vehicule
Vehicule::affiche(); //appel à la fonction affiche() de //Vehicule
saisie(); //appel à la fonction saisie() de Voiture
}




3.4) Cas des fonctions et classes amies.

Une fonction amie étant par définition une fonction externe à la classe de base, celle-ci n'est pas héritée par la classe dérivée. Si la classe dérivée doit donner l'accès à ses membres privés ou protégés aux mêmes fonctions que la classe de base, celle-ci devront être de nouveau définies comme fonctions amies.

Concernant une classe amie, celle-ci est héritée dans la classe dérivée mais elle ne peut accéder qu'aux données membres privées issues de la classe de base. Elle ne peut jamais accéder aux nouveaux membres de la classe dérivée.


3.5) Cas des constructeurs, du destructeur et de l'opérateur d'affectation.

Les fonctions constructeurs de la classe de base ne sont pas héritées dans la classe dérivée. Il en est de même avec le destructeur et les éventuels opérateurs d'affectation surchargés.

Lors de la construction d'une instance de la classe dérivée, le constructeur de la classe de base est d'abord appelé. Le constructeur de la classe dérivée est ensuite mis en œuvre. Inversement, lors de la destruction d'un objet de la classe dérivée, c'est d'abord le destructeur de la classe dérivée qui est appelé puis celui de la classe de base.

Dans le cas où l'utilisateur souhaite faire appel à des constructeurs différents des constructeurs par défaut, une liste d'initialisation est nécessaire. Cette liste se composent du constructeur souhaité de la classe dérivée en indiquant les paramètres suivie par ":" puis par le constructeur souhaité de la classe de base en indiquant les paramètres. L'initialisation des données membres supplémentaires se fait à l'intérieur de la fonction.


En résumé:

class Vehicule
{
public:
Vehicule(char *nom, int place);
…
};

class Voiture: public Vehicule
{
private:
int _cv;
public:
Voiture(char *n, int p, int cv);
}


Voiture::Voiture(char *n,int p,int cv): Vehicule(n,p)
{
_cv=cv;
}






4) Gestion de fichiers.

4.1) Généralités.

Les différents programmes réalisés dans les précédents TP manipulaient des données que nous leur fournissions par saisie. Une seconde manière de saisir les données consiste à lire celles-ci à partir d'un fichier. De la même manière, les résultats d'un programme peuvent être stockées dans un fichier.

D'une manière générale, les actions élémentaires que vous effectuerez sur des fichiers sont les suivantes:
- l'ouverture ou la création du fichier.
- l'écriture ou la lecture dans ce fichier.
- le déplacement à l'intérieur de ce fichier.
- la fermeture du fichier.

L'action d'ouverture de fichier peut se faire suivant deux modes: le mode texte et le mode binaire. En mode texte, les lectures et écritures des caractères de fin de ligne sont interprétées et converties. Cette conversion dépend du système d'exploitation. En mode binaire, il n'y a aucune interprétation lors des opérations de lecture et d'écriture.

En C++, les accès à des fichiers s'effectuent en manipulant des flots. Nous avons rencontré les flots d'entrée/sorties standards lors du premier TP: cin, cout, cerr et clog. La première action à entreprendre sera donc d'associer un flot au fichier.

Pour réaliser ces actions élémentaires, le langage C++ fournit 3 classes de base définies dans le fichier "fstream.h" (à inclure dans votre programme):


- ifstream: classe dérivée de istream et de fstreambase permettant l'accès en lecture seule

- ofstream: classe dérivée de ostream et de fstreambase permettant l'accès en écriture seule

- fstream: classe dérivée de iostream et de fstreambase permettant l'accès en
lecture/écriture


La classe fstreambase fournit des méthodes communes. Pour des raisons de performance, toute lecture/écriture vers un flot associé à un fichier s'effectue à travers un buffer. Cette mémoire tampon est une instance de la classe filebuf.

Déclarer un flot sur fichier de type ifstream, ofstream ou fstream revient donc à déclarer une instance d'une de ces 3 classes:

ifstream file1; //Déclaration d'une variable flot "file1" sur un fichier qui sera //accessible en lecture seule. Le constructeur par défaut est mis en //œuvre: aucun fichier n'est encore ouvert.

ofstream file2; //Déclaration d'une variable flot "file2" sur un fichier qui sera //accessible en //écriture seule.

fstream file3; //Déclaration d'une variable flot "file3" sur un fichier qui sera //accessible en lecture/écriture.


L'association entre un flot et un fichier peut alors s'effectuer à 2 moments:

- à l'ouverture du fichier avec la méthode open() qui compte comme arguments: le nom du fichier, le mode d'accès, et les droits du fichier si il y a création de celui-ci.

OU

- à la déclaration d'un flot de type ifstream, ofstream ou fstream en utilisant un constructeur différent du constructeur par défaut. Ce constructeur reprend alors la syntaxe de la méthode open().


4.3) Ouverture et/ou création de fichier.

Comme nous l'avons vu précédemment, l'ouverture d'un fichier se fait soit par un constructeur soit par la méthode open():

ifstream(file,mode,nprot)
ofstream(file,mode,nprot)
fstream(file,mode,nprot)
open(file,mode,nprot)

Le paramètre file indique le nom du fichier à ouvrir sous la forme d'une chaîne de caractère. L'argument mode permet de préciser comment est ouvert le fichier. Pour cela, la classe ios fournit une liste de spécificateurs qui peuvent être combinés dans un OU logique:


modeSignificationios::appmode ajout; les données sont écrites à partir de la fin de fichierios::atese positionne à la fin du fichierios::inmode lecture ios::outmode écritureios::binaryécriture sans interpréter les caractères de fin de ligneios::truncremet à zéro le fichierios::nocreateprovoque une erreur si le fichier n'existe pasios::noreplaceprovoque une erreur si le fichier existe déjà

Notons que déclarer une instance de la classe ifstream revient à positionner ios::in, qu'une instance de la classe ofstream revient à positionner ios::out et qu'une instance de la classe fstream revient à positionner ios::in|ios::out.


Concernant le paramètre nprot, sa valeur par défaut est ios::openprot et correspond aux droits 0644 (rw-r--r--) que nous connaissons dans le système d'exploitation UNIX.







Pour résumé, l'exemple suivant rassemble différentes manières d'ouvrir un fichier en l'associant à un flot:

#include
#include
#include
using namespace std;

void main(void)
ofstream f1,f2; //déclaration de flots sur fichier accès en écriture seule
//c'est le constructeur par défaut qui est utilisé
ifstream f3("donnee.txt"); //déclaration d'un flot avec ouverture d'un fichier
//en lecture seule
f1.open("data.txt",ios::trunc|ios::binary); //ouverture d'un fichier avec remise a
//zéro de celui-ci et en mode binaire
f1.close();

f3.open("data.txt"); //ouverture d'un fichier en écriture seule
f3.close();
}


4.4) Lecture et écriture.

Comme pour les entrée/sorties standards, les opérateurs >> et