Vous êtes sur la page 1sur 127

Université Chouaib Doukkali

SMA

Langage C++

Hassan Silkan

Université Chouaib Doukkali, Faculté des Sciences, Laboratoire LAROSERI, El Jadida.


Silkan_h@yahoo.fr
Langage C++
Un peu d'histoire
C++ se base essentiellement sur 2 langages:
 Simula 67 (1967) crée pour le traitement des problèmes de simulation, dont il
hérite le concept objet ( un programme autonome actif pouvant communiquer et se
synchroniser avec d'autres objets) .
 Langage C (1972) aux Bell Labs.
Bjarne Stroustrup (Bell Labs), le concepteur du C++, désirant ajouter au C les
classes de simula,créa le C++ après plusieurs version il aboutit en 1983 à une version
stable.
Langage C++
C++ versus
C++ dispose d'un certain nombre de spécificités par rapport à C en dehors de l'orienté
objet:
 Les commentaires
 L'emplacement libre des déclarations des variables
 Les arguments par défaut
 La surcharge (surdéfinition) des fonctions
 Les opérateurs new et delete
 Les fonctions en ligne ( inline)
 Les références
 ...
Langage C++
La fonction principale
La fonction main() est le point d'entrée de tout programme C++. Elle peut être
définie de 2 manières:
 Pour les programmes sans paramètres: int main() {....}
 Pour les programmes avec paramètres:
int main( int argc, char* argv[]){...}
où argc: le nombre de paramètres et argv[]: tableau de paramètres

Les commentaires
 Sur plusieurs lignes: /* .............comme en C...................*/
 Sur une seule ligne: //.... spécifique C++......
Langage C++
Les E/S
Entrées/sorties fournies à travers la librairie < iostream>
 cout << expr1 << … << exprn
 Instruction affichant expr1 puis expr2, etc.
 cout : « flot de sortie » associé à la sortie standard (stdout)
 << : opérateur binaire associatif à gauche, de première opérande cout et de
2ème l’expression à afficher, et de résultat le flot de sortie
 << est l’opérateur surchargé (ou sur-défini)⇒ utilisé aussi bien pour les
chaînes de caractères, que les entiers, les réels etc.
 cin >> var1 >> … >> varn
 Instruction affectant aux variables var1, var2, etc. les valeurs lues au clavier.
 cin : « flot d’entrée » associée à l’entrée standard (stdin)
 >> : opérateur similaire à <<
Langage C++
Les types de base
 Le type d’une donnée détermine :
 La place mémoire (sizeof())
 Les opérations légales
 Les bornes
 Déclaration et initialisation de variables :
bool var_bool = true; // variable boléenne nouveu type en C++
int i = 0; // entier
long j = 123456789; // entier long
float f = 3.1; // réel
double pi = 3.141592653589793238462643; // réel à double précision
char c=‘a’; // caractère
 « Initialisation à la mode objet » :
int i(0) ;
Long l (123456789);
Langage C++
Les constantes
 Le qualificatif const peut être utilisé pour une expression constante:
const type_var var=cte;
 Une expression déclarée avec const a une portée limitée au fichier source qui la
contient.

Exemple:
const int N=5; // par convention une constante est écrite en majuscule
int t[N]; // en C il fallait #define N 5
Langage C++
Les références
 une référence sur une variable est un identificateur qui joue le rôle d'un alias
(pseudo) de cette variable.
Syntaxe: type &nom_ref = var;
exemple:
int n;
int &rn=n; // rn est une référence de n
n=10;
cout<< rn; //affiche 10
 une référence ne peut être vide, elle doit toujours être initialisée lors de sa
déclaration, i.e : int &rn ; // erreur!
 Il est possible de référencer des valeurs numériques, dans ce cas il faut les
déclarer comme constantes, i.e: int &rn=3; // erreur!
const int &rn=3; // OK
 Les références et les pointeurs sont liés.
Langage C++
Déclaration des fonctions
 L'utilisation d'une fonction sans aucune déclaration ou définition au préalable est
une erreur à la compilation.
 Le prototype doit figurer dans tout fichier source qui utilise cette fonction et ne
contenant pas sa définition.
 Une fonction en C++ doit spécifier son type de retour, void si elle ne retourne
rien.
fct(int, int); // erreur!
void fct(int, int); //OK
 int fct(void); int fct();
Langage C++
Transmission des arguments
En C++ il y a 3 méthodes de passage des variables en paramètres à une fonction:
 Passage par valeur: la valeur de la variable en paramètre est copiée dans une
variable temporaire. Les modifications opérées sur les arguments dans la
fonction n'affectent pas la valeur de la variable passée en paramètre.
 Passage par adresse: consiste à passer l'adresse d'une variable en paramètre.
Toute modification du paramètre dans la fonction affecte directement la variable
passée en paramètre.
 Passage par référence: le passage par adresse présente certains inconvénients,
pour résoudre ces inconvénients, C++ introduit le passage par référence.
En pratique, il est recommandé ( pour des raisons de performances) de passer par
référence tous les paramètres dont la copie peut prendre beaucoup de temps.
Langage C++
Arguments par défaut
 C++ offre la possibilité de donner des valeurs par défaut aux paramètres d'une
fonction ( exo TD).
 Une fonction peut définir des valeurs par défaut pour tous ses paramètres ou
seulement une partie.
 Les valeurs par défaut doivent être mentionnées soit dans le prototype de la
fonction soit dans sa définition.
 Les paramètres ayant une valeur par défaut doivent être placés en dernier dans la
liste des arguments.
void fct ( int = 33 , int); //erreur!
Langage C++
Surcharge des fonctions
 La surcharge (surdéfinition) des fonctions consiste à donner un même nom à
plusieurs fonctions.
int max(int a, int b); // fonction 1
int max( int a, int b, int c); // fonction 2
int max( int* tab, int taille); // fonction 3
 Pour différencier entre deux fonctions qui portent le même nom, le compilateur
regarde le type et le nombre des arguments effectifs: la liste des types des
arguments d'une fonction s'appelle la signature de la fonction.
 La surcharge n'est acceptable que si toutes les fonctions ont des signatures
différentes, et n'a un sens que si les surdéfinitions ont un même but.
 Il est également possible de surcharger les opérateurs( voir les classes)
Langage C++
Les fonctions inline
 Une fonction ''inline'' est une fonction dont les instructions sont incorporées par le
compilateur à chaque appel.
Syntaxe: inline type fonct( arguments...) {… … }
 Les fonctions ''inline'' permettent de gagner au niveau temps d'exécution, mais
augmentent la taille des programmes en mémoire.
 Contrairement aux macro dans C, les fonctions ''inline'' évitent les effets de bord (
dans une macros l'argument peut être évalué plusieurs fois avant l'exécution de la
macro).
Langage C++
Allocation dynamique
En C++, les fonctions malloc et free sont remplacées avantageusement par les
opérateurs unaire new et delete.
main()
{ int *pi = new int;
int *tab = new int[10];
if ((pi != NULL) && (tab != NULL))
{
...
delete pi;
delete [] tab;
}
}
Classes et Objets
Définition d'une classe
La déclaration d'une classe consiste à décrire ses membres (membres données et
prototypes de ses fonctions membres) groupés en sections. Chaque section est
étiquetée par l'un des mots clés : private, public, ou protected, qui précisent le mode
d'accès aux membres contenus dans la section.
 private: accès autorisé seulement par les fonction membres
 public: accès libre
 protected: accès autorisé seulement dans les fonctions membres de la classe et de
ses dérivées (voir héritage).
Pour déclarer une classe, on utilise le mot clé class.
Classes et Objets
Exemple
class Point
{
private: // membres privés par défaut
int x;
int y; Données membres ( ou attributs) privés
public: // membres publiques
void initialise(int,int);
void deplace(int,int); Méthodes public
void affiche();
} ;
 La mention d'accès par défaut dans une classe est private.
 La définition d'une classe consiste à définir les prototypes des fonctions membres.
Pour les définir on utilise l'opérateur de portée (::) :
type nom_class::fct(arguments) {……}
Classes et Objets
 Au sein de la définition d'une fonction membre, les autres membres (privés ou
publiques) sont directement accessibles (il n'est pas nécessaire de préciser le nom
de la classe):
void point::initialise(int abs, int ord)
{
x = abs;
y = ord;
}
Remarques:
 Toutes les possibilités offertes par C++ pour les fonctions restent valables pour les
fonctions membres (surcharge, arguments par défaut, …).
 Toute fonction membre définie dans sa classe (dans la déclaration de la classe) est
considérée par le compilateur comme une fonction inline. Le mot clé inline n'est
plus utilisé.
Classes et Objets
Utilisation d'une classe
 Un objet (ou instance) nom_objet d'une classe, nommée nom_classe est déclaré
comme une variable de type nom_classe :
nom_classe nom_objet;

 On peut accéder à n'importe quel membre publique d'une classe en utilisant


l'opérateur (.) (point). Par exemple:
Point A;
……
A.initialise(10,12); // appel de la fct membre initailise de la classe 'Point'
//Cout<<'' l'abscisse du point A est'' <<A.x<<endl; //erreur car x est un attribut
privé!!
A.affiche();
Classes et Objets
Constructeur/Destructeur
 C++ permet l'utilisation de fonctions membres dites constructeurs et destructeur qui
sont implicitement appelées respectivement lors de la création et la destruction d'un
objet.
 Le(s) constructeur(s) sont des fonctions membres qui portent le même nom que leur
classe. Ces constructeurs sont appelés après l'allocation de l'espace mémoire destiné
à l'objet.
 Un constructeur peut être surchargé et avoir des arguments par défaut.
Classes et Objets
Constructeur / Destructeur
Exemple
Class Point
{ int x;
int y;
public: Remarque: Même si le constructeur ne
Point(int,int); // constructeur retourne aucune valeur, il est déclaré et défini
void deplace(int,int); sans le mot clé void .
void affiche();
};
la définition du constructeur sera de la forme:
Point::Point(int abs, int ord)
{ x = abs;
y = ord;
}
Classes et Objets
Constructeur/Destructeur
 Pour déclarer une instance d'une classe ayant un constructeur, on doit spécifier les
valeurs des arguments requis par le constructeur.
Point A(2,5);
Point B; // erreur , car on a déclaré la façon de construire les objets
 Le destructeur est une fonction membre qui porte le même nom que sa classe,
précédé du symbole (~). Le destructeur est appelé avant la libération de l'espace
associé à l'objet.
 Un destructeur ne peut pas être surchargé.
Classes et Objets
Constructeur/Destructeur
 Le destructeur est une fonction qui ne prend aucun argument et ne renvoie aucune
valeur.
 En pratique les destructeurs sont utilisés pour libérer d'éventuels emplacements
mémoire occupée par des membres données.
Exemple:
class Point
{ int x, y;
public:
Point(int,int); // constructeur
~Point(); // destructeur
};
La définition du destructeur sera de la forme:
Point::~Point()
{…}
Classes et Objets
Exemple
Considérons une classe Tab_entiers, qui permet de traiter des tableaux d'entiers dont les
dimensions sont fournies en données. Le constructeur aura donc la tâche d'allouer
dynamiquement l'espace mémoire nécessaire pour l'instance à créer et le destructeur doit libérer
cette zone.
/*----------- définition du constructeur ---------------------*/
Tab_entiers::Tab_entiers(int n)
class Tab_entiers
{ nb = n;
{ int nb;
tab = new int [nb];
int * tab;
}
public:
/*---------- définition du destructeur -----------------------*/
Tab_entiers(int); // constructeur
Tab_entiers::~Tab_entiers()
~Tab_entiers(); // destructeur
{ delete tab;
……
}
};
Classes et Objets
Affectation entre objets
 C++ autorise l'affectation d'un objet d'un type donnée à un autre objet de même
type. Dans ce cas il recopie tout simplement les valeurs des membres données
(privés ou publiques) de l'un dans l'autre.
Point A,B; // déclare deux instances de la classe Point
A.initialise(2,5); // A.x = 2 et A.y = 5
B =A; // B.x = 2 et B.y = 5
 Les pointeurs ne sont pas pris en considération dans un cas simple d'affectation :
Si parmi les membres données, se trouve un pointeur, l'emplacement pointé ne
sera pas recopié.
Classes et Objets
Attribut statique
 Un membre donnée déclaré avec l'attribut static est une donnée partagée par toutes
les instances d'une classe.
 Un membre donnée statique est initialisé par défaut à zéro. Mais :
 Il doit être défini à l'extérieur de la déclaration de la classe, même s'il est privé,
en utilisant l'opérateur de porté (::).
 Ne peut être initialisé à l'intérieur de la classe.
 L'accès à un membre donnée statique d'une classe suit les mêmes règles que les
autres membres. D'autre part, un membre donnée statique est une donnée qui existe
même si aucun objet de cette classe n'est déclaré, dans ce cas l'accès se fait à l'aide
du nom de la classe et l'opérateur de porté (::).
Classes et Objets
Exemple
class cpt_obj
{ static int nb_obj;
int a;
public:
cpt_obj(int); // constructeur
……
};
/*-------------------------------- définition du membre statique -----------*/
int cpt_obj::nb_obj; // par défaut nb_obj=0
/*------------------------ définition du constructeur -------------------------*/
cpt_obj::cpt_obj(int n) {
a = n;
cpt_obj++;
}
Classes et Objets
Exploitation des classes dans des projets C++
Pour les applications nécessitant beaucoup de classes, il est souhaitable que
celles-ci figurent dans des fichiers différents. On travaille alors de la manière
suivante :
 les déclarations des classes sont faites dans des fichiers d’extension .h (fichiers
d’entête)
 les définitions des fonctions membres sont dans des fichiers d’extension .cpp
 l’utilisation de ces classes apparaît finalement dans un fichier d’extension .cpp
contenant la fonction void main(void).
Classes et Objets

 #ifndef, #define et #endif sont ajoutés aux fichiers include pour que le fichier
ne soit inclus qu’une seule fois lors d’une compilation.
 dans tout programme utilisant la classe nom_classe, on doit inclure le fichier
d'entête ''nom_classe.h''. Un tel programme doit aussi pouvoir accéder au
module objet résultant de la compilation du fichier source contenant la
définition de la classe.
Classes et Objets
Objets transmis en argument
Considérons une classe T et une fonction F dont l'un des paramètres est un
objet de T transmis par valeur, par adresse ou par référence. Soit U une instance de
T transmis en argument à F, alors:
1. Si F est une fonction membre de T, elle aura accès à tous les membres données
de U, sinon elle n'aura accès qu'aux membres publiques de U.
2. Si la transmission de U se fait par valeur, il y a recopie des membres données de
U dans un emplacement locale à F, ce qui entraîne certains problèmes si la classe
contient des pointeurs.
Classes et Objets
Exemple
Définir une fonction qui permet de comparer deux instances de la classe
Point. Cette fonction devra retourner "true" si les deux objets coïncident et "false"
sinon.
La comparaison nécessite l'accès aux coordonnées des points, qui sont des
données privés, par suite, la fonction doit être une fonction membre de la classe.
La déclaration de la fonction dans la classe sera :
bool coincide(Point);
Et sa définition:
bool Point::coincide(Point pt)
{
return ( (pt.x == x) && (pt.y == y));
}
Classes et Objets
Objet fourni en valeur de retour
Etant donné une classe T et une fonction F qui a l'une des formes suivantes :
T F(arguments); // retour par valeur
T * F(arguments); // retourne l'adresse
T & F(arguments); // retourne une référence
Alors F aura accès à tous les membres de l'objet retourné si elle est une fonction
membre de T, si non elle n'aura accès qu'aux membres publics de la classe.
 Notez bien que d'une manière générale, une fonction ne doit pas retourner un
pointeur (ou une référence) sur une variable locale, du fait que la zone mémoire
occupée par une variable locale à une fonction est automatiquement considérée
comme libre à la fin de la fonction. Ainsi, par exemple :
int * fct_adr() { int n; … …, return &n}
int & fct_ref() { int n; … …, return n}
fournirons des résultants imprévisibles et erronés.
Classes et Objets
Exemple
On désire définir la fonction symetrique() qui permet de retourner le symétrique
d'un point de la classe Point.
Cette fonction doit être une fonction membre de la classe Point, puisqu'elle doit
accéder aux coordonnées du point, qui sont des données privées. La valeur de retour
sera de type Point La déclaration de la fonction dans la classe sera :
Point symetrique();
et sa définition
Point Point::symetrique()
{ Point pt;
pt.x = -x; pt.y = -y;
return pt;
}
Classes et Objets
Fonctions membres statiques
On distingue deux types de membres :
 Membres d'instance : membres associés à une instance de la classe.
 Membres de classe : membres associés à la classe et qui ne dépendent d'aucune
instance de la classe.
Les membres de classe sont déclarés avec l'attribut static, et existent
même si aucun objet de la classe n'est crée.
Notons qu’on peut définir un membre donnée statique comme on peut
définir une fonction membre statique. L'accès à ces membres se fait avec
l'opérateur de résolution de portée (::) précédé par le nom de la classe ou d'un
quelconque objet de la classe
Classes et Objets
// Corps de la classe : POINT.CPP
Exemple: #include "Point.h"
// definition obligatoire du membre donné statique
// Interface de la classe : POINT.H
int point::nb_obj;
#ifndef POINT_H Point::Point(int abs, int ord)
#define POINT_H {
x = abs; y = ord;
#include <iostream.h> // utilisé dans affiche() nb_obj++;
class Point{ }
Point::~Point()
int x; {
int y; nb_obj--;
}
static int nb_obj;
void Point::affiche()
public: {
Point(int = 0, int = 0); cout << "(" << x << "," << y << ")" << endl;
}
~Point(); // definition de la fonction membre static
void affiche(); void Point::affiche_nbobj()
{
static void affiche_nbobj();
cout<< ''le nombre d'objets est''<<nb_obj<<endl;
}; }
#endif ----
Classes et Objets
Exemple:
// Programme test
#include "Point.h"
void main()
{ //acces à la fonction membre static avant la création des objets
Point::affiche_nbobj();
// cout << Point::nb_obj ; // erreur : nb_obj est privée
// Appel de la fct membre en utilisant un objet
Point A;
A.affiche_nbobj();
// Appel de la fonction membre statique en utilisant le nom de la classe
Point B(5,6);
Point::affiche_nbobj();
}
Classes et Objets
Les fonctions membres constantes
Les objets, comme les autres types de C++, peuvent être déclarées constants avec
l'attribut const. Dans ce cas, seules les fonctions membres déclarées et définies avec
l'attribut const peuvent être appelées par des objets constants.
// déclarations
Exemple: T u; // instance non constante
class T { … ... const T v; // instance constante
// appels
public:... u.F(…); // OK
type_a F(...); // fct membre ordinaire v.F(…) ; // erreur: instance constante
u.G(…) ; // OK
type_b G(…) const; // fct membre constante v.G(…); // OK
type_c K(const T); // fct avec argument constant
T w;
};
u.K(v); //OK
u.K(w); // OK
v.K(w); // erreur:instance constante et fct non
constante

Remarque: Une méthode constante peut être appelée sur un objet variable ou constant.
Classes et Objets

On adoptera donc la discipline de programmation suivante :

 méthode d’accès aux données ou « accesseur » : il s’agit des méthodes qui


retournent ou affichent des données de l’objet sans les modifier. Les
accesseurs doivent être des méthodes constantes.
 méthode de modification des données ou « modificateur » ou « mutateur » :
il s’agit des méthodes qui modifient les données de l’objet. Un modificateur
ne doit donc pas être appelé sur un objet constant. Par conséquent, un
modificateur ne doit surtout pas être déclaré comme méthode constante.
Classes et Objets
Déclaration et initialisation des objets
Les objets suivent les mêmes règles que les variables ordinaires, nous
distinguerons alors :
 Les objets globaux : ceux qui sont déclarés en dehors de tout bloc.
 Les objets automatiques : ceux qui sont déclarés au sein d'un bloc
 Les objets statiques : ce sont les objets locaux statique (définie avec le mot clé
static)
Classes et Objets
Cas d'une classe sans constructeur
 Les données membres des objets globaux et statiques, qui ne sont pas des
pointeurs, seront initialisés par défaut à 0.
 L'initialisation explicite des objets lors d'une déclaration ne peut se faire qu'avec
des objets de même type, comme par exemple :
T a;
T b = a;
où T est une classe. Dans ce cas, le compilateur fera une copie simple des valeurs
des membres données de a dans ceux de b.
 L'utilisation d'une classe sans constructeur et comportant un pointeur est
fortement déconseillée, du fait qu'aucune initialisation implicite ne sera parfaite et
que lors de l'initialisation d'un objet par un autre, les deux objets concernés
partageront la même zone mémoire pointée par le pointeur
Classes et Objets
Cas d'une classe avec constructeur
 Pour une telle classe, toute déclaration doit comporter une initialisation. Ainsi,
pour déclarer par exemple un objet u d'une classe T, on doit utiliser l'une des
syntaxes suivantes :
syntaxe 1: T u=v;
syntaxe 2: T u(liste_des_valeur);
syntaxe 3: T u = T(liste_des_valeur);
Dans syntaxe 1, v est un objet de la classe T (défini antérieurement).
Les syntaxes 2 et 3 sont équivalentes. Dans ces deux formes, liste_des_valeur
est une liste de valeurs qui correspond à la liste des arguments du constructeur, en
tenant compte des valeurs par défaut définies par le constructeur et des surcharges
éventuelles du constructeur (autrement dit, T(liste_des_valeurs) doit être un appel
valable de la fonction membre T)
Classes et Objets
Exemple:
class T
{
int i;char c;
public:
T(int n, char cc = 'a' ){i=n; c=cc;}
……
};
T a(5,'A'); // ou T a=T(5,'A')
T b = T(3); // ou T b(3) et équivalent à T b(3,'a')
T c = a;
Classes et Objets
Cas d'une classe avec constructeur (suite)
Par ailleurs, notons les cas particuliers suivants:
 Si tous les arguments du constructeur ont une valeur par défaut T u(); et T u;
seront équivalentes.
 Si la classe ne comporte qu'un membre donnée du type de base T u(valeur); et T
u = valeur; seront équivalentes. Dans la deuxième il y aura une
conversion implicite du type de valeur vers T.
Exemple:
class T{
float z;
public:
T(float x =0.0){z=x;}
……
};
//La déclaration
T u = 1.2; //conversion implicite float->T
T u(1.2); // équivalente à la première
Classes et Objets
Constructeur par recopie (copy constructor)
Considérons une classe T, dont l'un des membres données est un
pointeur nommé adr. Cette classe doit alors comporter un constructeur qui
alloue dynamiquement une zone mémoire à ce pointeur pour l'initialiser et
un destructeur qui libère cette zone mémoire lors de destruction des objets.
Dans ce cas, si
T u = v; // où v est un objet de la classe T
Il y aura une copie simple des valeurs des membres données de v dans
ceux de u. Par suite, les pointeurs u.adr et v.adr désigneront la même
adresse, ce qui posera deux problèmes :
♦ Toute modification contenu de *adr de l'un des objets se fera aussi pour l'autre.
♦ La destruction de l'un des objets, entraînera la destruction du pointeur du
deuxième.
Classes et Objets
Exemple // --------------- Définition des fonctions membres
T::T(int n, int p)
#include <iostream.h> {
i = n;
//------------ Déclaration de la classe
pi = new int;
class T{ *pi = p;
int i; }
T::~T()
int *pi; {
public: if(pi != NULL)
delete pi;
T( int = 0, int = 0); }
~T(); void T::affiche()
{
void affiche();
cout << "(" << i << "," << *pi << ") --> " << pi <<
void modifier(int,int); endl;
}; }
void T::modifier(int n, int p)
{
i = n ; *pi = p;
}
Classes et Objets
Exemple (suite)
// ----------------------------------------- Test
void main()
{
T u;
cout << "u : ";u.affiche();
// initialisation d'un objet avec un autre
T v = u;
cout << "v : ";v.affiche();
// on modifie v
cout << "\n------------Modification" << endl;
v.modifier(2,2);
cout << "v : ";v.affiche();
cout << "u : ";u.affiche();
}
Classes et Objets
Constructeur par recopie (suite)
 Pour résoudre ce type de problèmes, C++ offre la possibilité de définir un constructeur particulier approprié à
ce genre de situation. Ce constructeur est appelé constructeur par recopie (copy constructor) et il est déclaré
comme suit:
T ( T &);
 Le code du constructeur par recopie doit contenir les instructions nécessaires pour créer un nouvel objet à
partir de l'objet passé en paramètre.
Exemple:
On ajoute à la classe T de l'exemple précédent , un constructeur par recopie définie comme suit :
T::T( T & v)

{ i = v.i;

pi = new int;
*pi = *(v.pi);
}

et on refait le même test que dans l'exemple précédent, pour montrer que les problèmes posés par l'initialisation
d'un objet par un autre sont bien résolus.
Classes et Objets
Tableau d'objets
 En théorie, un tableau peut posséder des éléments de n'importe quel type. Ainsi
nous pouvons déclarer un tableau de N objets d'une classe T par :
T tab[N];
Or, du fait qu'on ne peu déclarer un objet sans l'initialiser, cette déclaration ne
sera possible que si la classe T admet un constructeur sans arguments (ou
un constructeur dont tous les arguments ont des valeurs par défaut).
 Ces mêmes remarques s'appliquent pour les tableaux dynamiques d'objets. Une
déclaration de type :
T * adr = new T[N];
nécessite aussi un constructeur sans arguments.
Classes et Objets
Objet d'objets
Une classe peut comporter un membre donnée de type classe.
Considérons alors la situation suivante, où la classe T comporte un membre
donnée de type classe A :
class A{
……
public:
A(liste_arguments_a);

};
class T{
A a;

public:
T(liste_arguments);

};
Classes et Objets
Objet d'objets (suite)
Lors de la création d'un objet de type T, il y aura appel du constructeur de T
puis un appel du constructeur de A, car la création d'un objet nécessite la définition
de tous les membres données de l'objet (en particulier le membre a de type A).
Par suite, la création d'un objet de type T ne sera possible que si A possède un
constructeur sans arguments.
Pour gérer ce genre de situation, C++ nous offre la possibilité de mentionner, dans la
définition du constructeur de T, la liste des arguments à fournir au constructeur de A
et ce de la manière suivante :
T::T (liste_arguments) : a (liste_arguments_a)
{……}
où liste_arguments_a est une sous liste de liste_arguments, valable pour le
constructeur de A.
Classes et Objets
Fonctions amies
Si une fonction Fct est “amie” (friend) d’une classe C1, alors Fct peut accéder aux
champs privés de C1.
Si une classe C2 est “amie” de C1, toutes les fonctions membres de C2 peuvent
accéder aux champs privés de C1.
Ces déclarations se font dans la définition de C1 :
c l a s s C1
{
...
f r i e n d type-ret Fct( param−de−F ) ;
f r i e n d c l a s s C2 ;
...
};
Classes et Objets
'Friend' en résumé
 Les amis d’une classe sont des classes ou des fonctions
 Les amis d’une classe peuvent accéder à toutes les méthodes et données membre de
la classe quel que soit le niveau de protection
 Les amis d’une classe sont définis à l’intérieur de la classe
 Violation parfois utile, mais très souvent déconseillée du principe d'encapsulation
Classes et Objets
La surcharge des opérateurs
En C++, les opérateurs définis pour les types de base sont traités par le
compilateur comme des fonctions, ce qui permet donc, avec la technique de la
surcharge, d'utiliser la plus part d'entre eux avec les types classe
Les opérateurs redéfinissables sont :

Les opérateurs qui ne peuvent être surchargés .

. .* :: ?: # ##
Classes et Objets

 Pour surcharger un opérateur X, on définit la fonction operatorX (par exemple


operator+ pour l'addition).
 L'implémentation de la surcharge d'un opérateur peut se faire soit comme une
fonction classique (amie d'une classe), soit comme une fonction membre d'une
classe.
 La surcharge d'un opérateur est appelée implicitement par le compilateur chaque
fois que l'opérateur est rencontré dans le code, mais elle peut être aussi appelée
explicitement.
Classes et Objets
surcharge d'opérateurs : syntaxe de déclaration
Syntaxe générale :
type_de_retour operator op(liste arg);
Le symbole op qui suit le mot clé operator doit obligatoirement être un opérateur
déjà défini pour les types de base
Exemple:
class Point
{int x,y;
…};
Prototype de la fonction amie operator+:
Point operator +(Point,Point) ;
Prototype de la fonction membre operator + :
Point operator +(Point) ;
Classes et Objets
Surcharge d'opérateurs (suite)
 La surcharge d’opérateurs doit conserver la pluralité (unaire,binaire) de l’opérateur
initial
 Opérateurs unaires : + - ++ -- ~ * & new delete (cast), etc ...
 Opérateurs binaires:
* / % + - << >> < <= > >= || && | & [], etc …
 L’opérateur . ne peut pas être surchargé
 Les opérateurs =,[], (), ->, new et delete doivent être redéfinis comme fonctions
membre d'une classe (et non comme fonctions amies)
Classes et Objets
Surcharge d'opérateurs: Fonction amie
 Les arguments de la fonction correspondent aux opérandes de l’opérateur
 Au moins un des arguments est de type classe
 Exemple :
class Point {int x,y; …};
Prototype de la fonction amie operator +:
Point operator +(Point,Point) ;
 déclarer l’amitié dans la classe Point
 définir la fonction amie
Classes et Objets
Surcharge d'opérateurs (suite)
Exemple:
#include <iostream.h> main()
class Point {
Point a(1,2), b(2,5) ;
{ int x,y ;
Point c ;
public : c=a+b;
Point (int abs = 0 , int ord = 0) }
{x=abs; y=ord; }
friend Point operator+ (Point,Point) ; Remarques :
expression a+b interprétée par le compilateur
};
comme l’appel : operator+ (a,b)
on pourrait écrire :
Point operator + (Point a, Point b) c = operator +(a,b);
{ Point p ;
p.x = a.x + b.x ; p.y = a.y + b.y ;
return p ;
}
Classes et Objets
Surcharge d'opérateurs: Fonction membre
 La première opérande de l’opérateur transmise implicitement :
l’objet auquel on applique la fonction membre
 Si l’opérateur est binaire, pas de contrainte de type imposé sur l’argument
explicite
Exemple :
class Point {int x,y; …};
Prototype de la fonction membre operator + :
Point operator +(Point) ;
Classes et Objets
Surcharge d'opérateurs (suite)
Exemple:
#include <iostream.h> main()
class Point {
{ x,y ; Point a(1,2), b(2,5) ;
public : Point c ;
c=a+b;
Point (int abs = 0 , int ord = 0)
}
{x=abs; y=ord; }
Point operator+ (Point) ; Remarques :
}; expression a+b interprétée par le compilateur comme
l’appel : a.operator+ (b)
Point Point :: operator + (Point b) on pourrait écrire :
{ Point p ; c = a.operator +(b);
p.x = x + b.x ; p.y = y + b.y ;
return p ;
}
Classes et Objets
Surcharge d'opérateurs (suite): Passage par référence
 La transmission des arguments peut se faire par référence (préférable pour objets
de grande taille)
 Prototype de la fonction amie :
Point operator +(Point & a, Point & b) ;
ou
Point operator +(const Point & a, const Point & b) ;
 Prototype de la fonction membre :
Point operator +( Point & b) ;
ou
Point operator +(const Point & b) ;
Classes et Objets
Surcharge d'opérateurs: opérateur d'affectation
Exemple :
Point a(1,2), b(3,4) ;
...
b=a;
 Si non explicite, opérateur d’affectation par défaut : recopie des valeurs de la
seconde opérande dans la première
 Doit être déclaré comme une fonction membre en C++

 Différences entre l'implémentation du constructeur par recopie et celle de la


surcharge de l'opérateur =:
 affectation d'un objet à lui-même possible
 avant affectation : 2 objets déjà construits
Classes et Objets
Forme canonique d'une classe
class A
{
public:
A(…) ; // constructeur
A(const A &) ; // constructeur de recopie
~A(…) ; // destructeur
A & operator = (const A &) ; // opérateur d’affectation
};
Classes et Objets
Surcharge d'opérateurs: opérateur de conversion
 Si un opérateur de conversion est défini, on peut affecter l’objet dans une
variable du type correspondant
 Doit être déclaré comme une fonction membre en C++
 Pas de type de retour spécifié :
type = nom de l’opérateur
 Pas de paramètre
 Retour de l’objet converti
Classes et Objets
Surcharge d'opérateurs: opérateur de conversion
Définition :
class Point
{ public:
operator double(); // opérateur unaire
private:
int x,y ;
};
Implémentation :
Point::operator double()
{ return sqrt(x*x+y*y) ;
}
Utilisation :
main()
{ Point pt(10,3) ;
double f ;
f = (double)pt ; // ou double (pt) ;
}
Heritage
A l'origine
Impératif de réutiliser
Les portions de code déjà écrites dans les classes utilisées pour des projets
antérieurs (comme cela se fait dans les modules en C).
Pourquoi?
recopier est peu valorisant
recopier est coûteux en développement (écriture, mise au point, tests)
recopier est coûteux en maintenance (multiplication des erreurs)
Heritage
L'idée
 Organiser ses propres classes en réutilisant les classes existantes (les
siennes ou celles des autres (bibliothèques,…))
 Une classe dérivée hérite de (récupère) toutes les données membre et
toutes les fonctions membre de la classe de base
Heritage
L'idée (suite)
Une classe dérivée peut
 accéder aux données membre et fonctions membre de sa classe de base selon
certaines règles (accès si public ou protected)
 ajouter des données membre et fonctions membre à sa classe de base
 redéfinir* certaines fonctions membre de sa classe de base
(*) définir des fonctions aux en-têtes identiques, à savoir noms identiques et
paramètres identiques. Différent de la surdéfinition ou surcharge!
Heritage
Le Principe
L'héritage simple structure un ensemble de classes en une hiérarchie.
Au sommet, on trouve la classe correspondant au concept le plus général.
Du sommet vers la base, on spécialise en cas de plus en plus particuliers.
La relation d'héritage:
est_un possède les caractéristiques de
Heritage
Le principe (suite)

Véhicule

Véhicule
Avion Voiture Bateau
Avion Voiture Bateau

Jeep Voilier
Jeep Voilier

Hydravion
Heritage
Résumé
 Permet de définir une classe qui enrichit ou spécialise une classe existante
 On peut dériver de une ou plusieurs classes (héritage multiple très dangereux)
 La classe dérivée peut accéder aux membres publics et protégés de la classe de
base
 La classe dérivée ne peut pas accéder aux membres privés de la classe de base
Heritage
Syntaxe
 Héritage simple:
class MaClass : public MaClass_de_base
{
...
};
 Héritage multiple:
class MaClass : public MaClasse_de_Base , public AutreClasse_de_deBase
{
...
};
Heritage
Construction
Quand un objet est construit, tous les constructeurs sont appelés
Les constructeurs des classes de base sont appelés AVANT les constructeurs des
classes dérivées
Exemple : Si A dérive de B qui dérive de C :
Le constructeur de C est appelé
Le constructeur de B est appelé
Le constructeur de A est appelé
Heritage
Exemple
class D
{public :
D(int,int) ;
};
class E : public D // E dérivée de D
{public :
E(int,int,int) ;
};
// initialisation de la classe de base
E::E(int x,int y,int z) : D(x,y)
{
}
Heritage
Constructeurs
 CAS 1 : Cas où le constructeur de la classe dérivée est synthétisé par le compilateur
(sans paramètres) : ce constructeur appelle le constructeur par défaut de la classe de
base (appel sans argument du constructeur synthétisé ou d'un constructeur défini
sans paramètres ou dont tous les paramètres ont une valeur par défaut)
class A class A
class A
{ {
{
private: private:
private:
public: public:
public:
A(); A(T1 a1, T2
};
}; a2);
};
class B : public A
class B : public A class B : public A
{
{ {
private:
private: private:
public:
public: ...}; public:
};
};
OK : le constructeur synthétisé de B appelle OK : le constructeur synthétisé de B NON : le constructeur synthétisé de B ne trouve
appelle le constructeur par défaut A pas de constructeur par défaut (défini sans
le constructeur par défaut A (ici synthétisé) paramètres ou avec paramètres par défaut) dans
défini sans paramètres
A
Heritage
Constructeurs (suite)
 CAS 2 : Un constructeur explicitement défini de la classe dérivée appelle le
constructeur de la classe de base en accord avec la liste d'initialisation dans l'en-
tête de sa définition. Si la liste ne mentionne pas de constructeur, c'est le
constructeur par défaut qui est appelé (sans paramètres).
Heritage
Appels Constructeurs
class A
{ private:
public:
A(T1 a1, T2 a2);
};
class B : public A // B dérivée de A
{ private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3) : A(b1,b2)
{
}
OK : le constructeur de B appelle le constructeur de A précisé dans la liste
d’'initialisation.
Heritage
Appels Constructeurs
class A
{
private:
public:
A();
A(T1 a1, T2 a2);
};
class B : public A
{
private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}
OK : le constructeur de B appelle le constructeur par défaut (sans paramètres et non synthétisé ici)
de A
Heritage
Appels Constructeurs
class A
{ private:
public:
};
class B : public A
{ private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}
OK : le constructeur de B appelle le constructeur par défaut
(synthétisé) de A .
Heritage
Appels Constructeurs
class A
{
private:
public:
A(T1 a1, T2 a2);
};
class B : public A
{
private:
public:
B(T1 b1, T2 b2, T3 b3);
};
// définition des méthodes
B::B(T1 b1, T2 b2, T3 b3)
{
}

NON : le constructeur de B ne trouve pas le constructeur par défaut de A . Pas de


constructeur synthétisé ici.
Heritage
Destruction
 Quand un objet est détruit, son destructeur et celui de toutes les classes de base sont
appelés
 Le destructeur de la classe dérivée est appelé en premier
 Exemple : Si A dérive de B qui dérive de C :
 Le destructeur de A est appelé

 Le destructeur de B est appelé


 Le destructeur de C est appelé
Heritage
Accès aux membres
Statut des membres de la classe dérivée en fonction du statut des membres de la
classe de base et du mode de dérivation.

 les attributs privés, mais accessibles par l’instance


 les attributs inaccessibles : ils occupent de la place mémoire, mais personne ne peut
plus y accéder, y compris l’instance elle-même.
Heritage
Héritage privé
But : masquage du legs de la classe de base reçu par la classe dérivée = technique
de fermeture des accès à la classe de base
Syntaxe :
class MaClass : private MaClasse_de_Base
{
...
};

1) Un utilisateur de la classe dérivée MaClass ne pourra pas accéder aux membres


publics de la classe de base
2) Les fonctions membres de la classe dérivée peuvent accéder aux fonctions et
membres publics et protégés de la classe de base
Heritage

Héritage privé (suite)


Quand l’utiliser ?
Toutes les fonctions utiles de la classe de base sont redéfinies dans la
classe dérivée et on ne veut pas laisser l’utilisateur du programme accéder aux
fonctions de la classe de base
(exemple : Pile dérive de Tableau)
Heritage
Héritage privé (suite)
Ce type d'héritage s'utilise lorsque la classe dérivée n'est pas un cas particulier
Exemple: de la classe de base (bien que sa définition s'appuie sur celle de la classe de
base).
class Table
{ class Pile : private
int nb; Table
double *tab; {
public: double *sommet;
Table(); public:
Table(int taille); Pile();
Table(const Table&); Pile(int taille);
~Table(); void empiler(double x);
Table& operator=(const Table&); double depile();
double& operator[](int); bool isEmpty();
}; };
L'implémentation de Pile s'appuie sur celle de Table, mais il est nécessaire de cacher à
l'utilisateur la possibilité d'accéder à n'importe quel élément de la pile par l'opérateur []; pour
cette raison on choisit l’héritage privé.
Heritage
Rétablissement des droits d'accès
Il est possible de rétablir les droits d'accès modifiés par la dérivation pour rétablir les
droits d'origine de ces attributs ou méthodes.
Le rétablissement ne concerne que les membres déclarés public ou
protected dans la classe de base.
class A class B : private A int main()
{ { {
public: B b;
public: using A::a1; b.a1 = 1; // OK
int a1; }; b.a2 = 1; // Illégal
int a2; return 0;
};
};
Heritage
Constructeur par copie
Rappel : le compilateur génère un constructeur par copie trivial si le
concepteur n'en écrit pas.
Le constructeur par copie généré pour une classe dérivée appelle
implicitement les constructeurs par copie des classes de base. Ce n'est pas le
cas si on écrit soi-même le constructeur par copie.
Heritage
Constructeur par copie
Heritage
Constructeur par copie
La meilleure solution consiste là encore à utiliser les listes
d'initialisation des constructeurs :
Heritage
Opérateurs
Tous les opérateurs sont hérités
Attention à l’opérateur = (affectation) :
surcharge de l’opérateur = dans la classe dérivée : il faut appeler celui de la classe de base
(pas d’appel implicite comme dans le cas du constructeur)
Heritage
Opérateurs (suite)
Si opérateur = non surchargé dans la classe dérivée:
 affectation de la partie héritée de la classe de base selon la surcharge de
l'opérateur = dans la classe de base
 affectation membre à membre (par défaut) pour les membres propres à la
classe dérivée
Heritage
Redéfinition des attributs
Il est possible de redéfinir un attribut dans la classe dérivée. L'attribut redéfini
masque celui issu de la classe de base. L'opérateur de résolution de portée (::) permet
cependant d'accéder à l'attribut masqué :

class A int x; Trois variables de


{ void B::f() même nom !!!
public: {
int x; x++; // incrémente B::x
}; A::x++; // incrémente A::x
class B : public A ::x++; // incrémente x
{ global
public: };
int x;
void f();
};
Heritage
Redéfinition des méthodes
De la même façon, une méthode masque toutes les méthodes de même nom
définies dans la classe de base.

class A int main()


{ {
public: B b;
void f(int); b.f(1); // Erreur : 'f' fonction ne prend pas de
void f(); paramètre
}; b.A::f(1); // OK
class B : public A b.f(); // OK, appelle B::f()
{ return 0;
public: };
void f();
};
Heritage
Conversions d’objets
Par un héritage public, une classe B dérivée de A est considérée comme une
"sorte" de A. Quel que soit l'objet a de type A et l'objet b de type B dérivé
publiquement de A, tous les services offerts par a sont aussi offerts par b
=> donc b peut remplacer a
Pour des classes en relation de dérivation publique, le compilateur effectue
certaines conversions implicites :
 objet de la classe dérivée => objet de la classe de base ;
 référence sur un objet de la classe dérivée => référence sur objet classe de base ;
 pointeur sur un objet de la classe dérivée => pointeur sur objet classe de base.
Cette conversion implicite n'existe pas si l'héritage est privé ou protégé.
Heritage
Conversions d’objets (suite) On réalise les appels :
X xob;
Soient les classes: Y yob;
class X {}; P pob;
class Y : public X {}; fx1(yob); // Classe dérivée => base
class P : private X {};
fx2(&yob); // Idem

fy1(xob); // Erreur, pas dans ce sens


fy2(&xob); // Erreur, pas dans ce sens

fx1(pob); // Erreur, héritage privé


fx2(&pob); // Erreur, héritage privé

xob = yob; // Classe dérivée => base


yob = xob; // Erreur, pas dans ce sens
Et soient les fonctions xob = pob; // Erreur, héritage privé
suivantes:
void fx1(X x); D’après les héritages choisis :
void fx2(X* x);  « Tous les Y sont des X », mais « Tous les X ne sont pas des Y »
void fy1(Y y);
void fy2(Y* y);  « Les P ne sont pas des X »

Le compilateur se charge de réaliser automatiquement les


conversions autorisées (ici seulement de la classe Y vers la classe X).
Heritage
Conversions d’objets (suite)

Pour un pointeur ou une référence, il est possible de distinguer :


 Le type statique du pointeur/référence : il peut être déterminé à la compilation, par une analys
 Le type dynamique : il est déterminé par la valeur courante, et peut changer en cours d'exécut
Heritage
Conversions d’objets (suite)
Grâce à ces conversions implicites de pointeurs et de références, tout objet peut
être traité comme un objet plus général. Cela permet de traiter collectivement un
ensemble d'objets de types différents :
Polymorphisme
L'idée
Le polymorphisme :
dans le prolongement de la surdéfinition et de la redéfinition.
 Surdéfinition ou surcharge (« overloading »): les fonctions ont le même nom, mais
le compilateur les distingue par la liste de paramètres
 Redéfinition (« overriding »): les fonctions membre ont exactement le même en-
tête (nom et paramètres identiques), mais le compilateur les distingue selon le type
déclaré de l'objet auquel on les applique
 Polymorphisme: les fonctions membre ont toujours le même en-tête, mais le
compilateur génère, pour celles qui sont déclarées virtuelles , des instructions
supplémentaires qui permettent de les distinguer lors de l'exécution selon le type
effectif de l'objet auquel on les applique, tout ceci dans les limites d'une même
hiérarchie d'héritage
Méthode virtuelle

 Lorsqu’une méthode est virtuelle dans une classe de base, elle est toujours
virtuelle dans toutes les classes dérivées
 Placerépète r virtual avant le type de retour de la fonction
 On virtual dans les classes dérivées pour la clarté (mais ce n’est pas
obligatoire)
Méthode virtuelle

 Remarque importante : Si p est déclaré comme un pointeur vers une classe de


base, p peut contenir un pointeur vers n'importe quelle classe dérivée de cette
classe de base.
La conversion de PCDERIVEE -> PCBASE est implicite.
Il est sous-entendu ici que la dérivation est publique
Méthode virtuelle
 L'appel d’une méthode virtuelle n'est plus traduit par un branchement à une
adresse connue d'avance, mais par une série d'instructions capable de
déterminer lorsque le programme s'exécute à quelle adresse il convient de se
brancher.
 Lorsqu’une méthode est virtuelle, c’est l’implémentation de la classe de l’objet
auquel elle est appliquée qui est appelée
Méthode virtuelle
SYNTAXE DE DECLARATION
class A
{ public:
A() {} ;
virtual bool IsA() const ;
};

class B : public A
{ public:
B() {} ;
virtual bool IsA() const ;
// virtual est optionnel dans la classe dérivée
};
Méthode virtuelle
SYNTAXE D’IMPLEMENTATION
bool A::IsA() const
{
return TRUE ;
}

bool B::IsA() const


{
return FALSE ;
}

c.-à-d. rien de spécial …


Méthode virtuelle
Utilisation
B dérive de A :

A* pA = new A ;
A* pB = new B ;
if (pA->IsA())
cout << " Objet de classe A ";
if (pB->IsA())
cout << " Objet de classe A ";
delete pA ;
delete pB ; // ERREUR !!!!
// Destructeur de B non appelé
Rappel :
En POO, on considère qu’un objet d’une classe dérivée peut « remplacer » un objet
de la classe de base
Méthode virtuelle
Remarque:
Toujours déclarer virtuel le destructeur d’une classe de base destinée à être
dérivée pour s’assurer d' une libération complète de la mémoire.
 Pas d’obligation de redéfinir une méthode virtuelle dans les classes dérivées
 Possibilité de redéfinir une méthode virtuelle d’une classe de base, par une
méthode virtuelle ou non virtuelle dans une classe Dérivée
Attention!! Nécessité de respecter le prototype de la méthode virtuelle redéfinie
dans une classe dérivée (même arguments et même type retour)
Méthode virtuelle pure

 Une méthode virtuelle pure est une méthode virtuelle déclarée dans une classe de
base, mais n’ayant pas d’implémentation dans cette classe
 Les autres méthodes de la classe peuvent appeler cette méthode
Méthode virtuelle pure
SYNTAXE DE DECLARATION
Ajouter = 0 à la fin de la déclaration de la méthode
class X
{ // Définition d’une fonction virtuelle pure
// =0 signifie qu’elle n’a pas de définition
// Attention, c’est différent d’un corps vide : { }
virtual bool IsA() const = 0 ;
};
Classe abstraite

 Une classe abstraite est une classe qui contient au moins une méthode virtuelle
pure
 Les classes dérivées d’une classe abstraite sont abstraites tant que toutes les
méthodes virtuelles ne sont pas implémentées (virtuelles pures)
 On ne peut pas créer un objet d’une classe abstraite
 Mais possibilité de définir des pointeurs et des références sur une classe abstraite
 Quand une classe est abstraite, il est obligatoire d’en dériver et d’implémenter
toutes les méthodes virtuelles pures .
Les entrées-sorties
Introduction
 Déjà rencontré :
int n;
cin >> n ; // flot d'entrée cin
cout << n ; // flot de sortie cout
cerr << ''message erreur''; //flot de sortie des erreurs
 Flot = « canal » :
 recevant de l’information, si flot de sortie
 fournissant de l’information si flot d’entrée
 Rôle des opérateurs << et >> :
 transfert de l’information
 formatage (éventuel)
 cout = flot prédéfini connecté à la sortie standard (écran)
(en C : fichier prédéfini stdout)
 cin = flot prédéfini connecté à l’entrée standard (clavier)
(en C : fichier prédéfini stdin)
Les entrées-sorties
Hiérarchie des classes IO

io s
io s
is t r e a m o s tre a m

is t r e a m o s tre a m
io s t r e a m

ifs t r e a m o fs tr e a m

fs tr e a m
Les entrées-sorties

Classe OSTREAM
 cout est un objet de la classe ostream
 #include <iostream.h>
ou
#include <iostream>
using namespace std ;
 opérateur << surchargé pour les types de base

ostream & operator << (type_de_base);

exemple: cout << " valeur : " << n ;


Les entrées-sorties
Classe OSTREAM: Fonctions membres principales
 ostream & put(char) ;
char c = 'a' ;
cout.put(c) ; // affiche le caractère c
 ostream & write(const char *,int) ;
char ptr[ ] = "bonjour" ;
cout.write(ptr,5) ;
// affiche 5 caractères à partir de l'adresse ptr
Les entrées-sorties
Classe ISTREAM
 cin est un objet de la classe istream
 #include <iostream.h>
 opérateur >> surchargé pour les types de base

istream & operator >> (type_de_base &) ;


exemple: cin >> n >> x ;
Les entrées-sorties

Classe ISTREAM: Fonctions membres principales


 int gcount() ;
// fournit le nombre de caractères lus par getline()

char ch[20] ;
int len ;
while (cin.getline(ch,20))
{ len = cin.gcount() ;
…}
 istream & read(char * t,int x);
// lecture de x bytes

char t[5] ;
cin.read(t,5) ;
Les entrées-sorties
Connexion d'un flot à un fichier
 #include <iostream.h>
#include <fstream.h>
 Ecriture dans un fichier :
créer un objet de la classe ofstream (dérive de ostream)
ofstream fic_out ("fic",ios::out) ;

nom de fichier mode d'ouverture


 Lecture d'un fichier :
créer un objet de la classe ifstream (dérive de istream)
ifstream fic_in ("fic",ios::in) ;

nom de fichier mode d'ouverture


Les entrées-sorties
Connexion d'un flot à un fichier (suite)
 Lecture et écriture dans un fichier :créer un objet de la classe fstream (dérive de
iostream, qui dérive de istream et ostream)
fstream fic ("fic",ios::in|ios::out) ;
 Ouverture d’un fichier : par le constructeur de la classe ou par la méthode open
des classes ifstream , ofstream et fstream
void open (const char * filename, openmode mode = in | out);
 Fermeture du fichier :
fic.close() ;
Les entrées-sorties
Exemple
L’ouverture d’un fichier est réalisé à l’aide de la méthode « open»
commune aux 3 classes,
#include <fstream.h>
int main( void )
{
ifstream f1; // instanciation de l’objet
f1.open("essai1.tmp"); // ouverture du flux de données
ofstream f2("essai2.tmp"); // combinaison des opérations
// ... ... ... ... ...
}
Les entrées-sorties
Exemple complet
But lire et écrire 1, 2, 3 dans un fichier!
#include <fstream>
#include <fstream>
#include <fstream> main()
{
void ecrire(char * nom_fic) {
Ecrire(''toto.txt'');
ofstream osf(nom_fic, ios::out);
Lire(''toto.txt'');
osf<<1<<'' ''<<2<<'' ''<<3; }
osf.close(); }
void lire(char * nom_fic){
int i; ifstream ifs(nom_fic);
while(!ifs.eof()){ ifs>>i; // ifs lit et met le résultat dans la variable i
If (!ifs.eof()) cout <<i<<'' ''<<endl;}
Les entrées-sorties

Surcharge des opérateurs << et >> pour les types


utilisateurs
 Opérateur prenant un flot en premier argument ,il doit être redéfinie en fonction
amie
ostream & operator << (ostream &, expression_de_type_classe &)
istream & operator >> (istream &, expression_de_type_classe &)
 Valeur de retour obligatoirement égale à la référence du premier argument
class point
{ int x, y ;
public :
point (int abs=0, int ord=0){ x = abs ; y = ord ; }
friend ostream & operator << (ostream &, point &) ;
friend istream & operator >> (istream &, point &) ;
};
Les entrées-sorties
// Redéfinition de l’opérateur << en fonction amie de la classe Point
ostream & operator << (ostream & sortie, point & p)
{ sortie << "(" << p.x << "," << p.y << ")" ; return sortie ; }
// Redéfinition de l’opérateur >> en fonction amie de la classe Point
istream & operator >> (istream & entree, point & p)
{ char c = '\0' ; // Si la saisie a été correcte, on affecte à p

int x, y ; bool ok = true ; if (ok=true) { p.x = x ; p.y = y ; }


entree >> c ; // saisie d’un caractère au clavier
// Statut d’erreur du flot géré par
if (c != '(') ok = false ; // un ensemble de bits d’un entier
else { entree >> x >> c ; // saisie de x (entier)
// clear (activation de bits d’erreur)
// et d’un autre caractère au clavier
// badbit (bit activé quand flot dans un état irrécupérable)
if (c != ',') ok = false ; // rdstate () pur activer le bit badbit sans activer les autres
else { entree >> y >> c ; // même chose pour y
else entree.clear (ios::badbit | entree.rdstate () ) ;
if (c != ')' ) ok = false ; }
} // on retourne le flux d'entrée
return entree ;
}
Les entrées-sorties
int main()
{
point b
cout << "donnez un point : " ;
if (cin >> b)
cout << "Affichage du point : " << b << endl ;
else cout << "** information incorrecte" << endl ;
}
Patrons(templates)
Patrons de fonctions
template <typename T> T min (T a, T b)
{
if (a < b) return a; Paramètre de type T
else return b ; (T = type quelconque)
} typename T ou class T
Condition d’utilisation de la fonction min():
2 paramètres de même type (ex. 2 int, 2 float, …)
min (3,7) ;
min(5.6,9.8) ;
Le compilateur fabrique (instancie) automatiquement la fonction min avec le type T
utilisé : c’est une fonction patron
Patrons(templates)
Patrons de fonctions
Pas possible de créer un .o d’un patron de fonction
 le mettre dans un fichier .h
Patrons(templates)

Patron de fonction : application à un type classe


class Point
{
public :
Point(int abs = 0, int ord = 0)
{ x =abs ; y = ord; }
int operator < (Point b)
{
return x*x+y*y < b.x*b.x+b.y*b.y;
}
private :
int x,y ;
};

main()
{
Point p1(2,5), p2(1,8),p3 ;
p3 = min(p1,p2) ;
}
Patrons(templates)

Patron de fonction: paramètres de type


 plusieurs paramètres de type:
template <typename T, typename U> T fct(T a, T* b, U c)
 Paramètres peuvent intervenir:
 dans l’en-tête de définition
 dans des déclarations de variables locales
 dans des instructions de type new, sizeof(), …
template < typename T, typename U> T fct (T x,U y,T z)
{…
Ta;
U *b ;
b = new U[10] ;
int n = sizeof(T) ;

a=x+y+z;
return a ; }
Patrons(templates)
Les patrons de classes
Écrire une définition de classe
Le compilateur l’adapte à différents types
template < typename T> class Point
{ public :
Point(T abs = 0, T ord = 0)
{ x =abs ; y = ord; } // définition en ligne
void affiche() ; // définition hors classe Exemple d'utilisation:
private : Point <int> p1(3,5) ;
T x,y ; Point <float> p2(3.5,6.7) ;
};
template < typename T> void Point<T>::affiche()
{ cout << " coordonnees : " << x << " " << y << endl ;
}
Patrons(templates)
Patrons de classes: Où?
Pas possible de fournir à un utilisateur une classe patron toute compilée
 la mettre dans un .h (y compris la définition des fonctions membres non en ligne)
Patrons(templates)
Patron de classe : paramètres expression
Exemple : Paramètre de type Paramètre expression

template <typename T, int n> class Tableau


{
T tab[n] ;
};
Les valeurs effectives devront être des constantes:

Tableau <int,4> t1 ;
Tableau <float,100> t2 ;

Vous aimerez peut-être aussi