Chap2 Courscpp
Chap2 Courscpp
Chap2 Courscpp
Chap 1:
Rappels C++
Pr SAADI Mostafa
1
Programmation Orientée Objets
Processus et procédures
Les normes ISO sont élaborées au travers de processus précis comprenant
plusieurs stades prédéfinis afin de créer un consensus à l’échelle d’un secteur
industriel.
La normalisation internationale est un processus multi-parties prenantes
impliquant l’industrie, la science, les milieux universitaires, les consommateurs et
les gouvernements.
L’ISO publie des normes, mais aussi d’autres référentiels comme les spécifications
publiquement disponibles (PAS), les guides, les spécifications techniques (TS), les
rapports techniques (TR) et les accords internationaux d’atelier (IWA).
Les procédures pour l’élaboration des normes ISO sont définies dans les Directives
ISO/CEI (en deux parties) et le Supplément ISO, trois documents essentiels qui
décrivent les procédures et les règles de rédaction à suivre par les comités
techniques de l’ISO.
Cette section présente les trois documents centraux qui décrivent les règles
procédurales fondamentales à suivre par les comités de l'ISO, à savoir:
Directives ISO/CEI, Partie 1: Procédures pour les travaux techniques
Directives ISO/CEI, Supplément - Procédures spécifiques à l'ISO
Directives ISO/CEI, Partie 2: Règles de structure et de rédaction des Normes
internationales
L'accès est également donné aux références normatives citées dans ces documents
centraux et aux Guides ISO. (Note: le visionnement des Références normatives est
soumis à un contrôle d'accès - un nom d'utilisateur et un mot de passe sont exigés).
Les formulaires à utiliser conjointement avec les trois documents centraux sont
disponibles pour un téléchargement sur www.iso.org/forms.
L'ISO/CEI JTC 1 (Technologies de l'information) a adopté les Directives ISO/CEI,
Partie 1 avec le Supplément JTC 1 (en anglais).
Critères de ''qualité'' d'un logiciel
L'exactitude
La robustesse
L'extensibilité
L'efficience
La portabilité
La réutilisabilité
La modularité
Programmation Orientée Objets
Programmation structurée
La construction d'un logiciel se base sur l'équation de WIRTH:
Algorithmes + Structures de données = Programme
La construction d'un programme structuré peut être basée soit:
Sur les traitements
Sur les données.
Concepts fondamentaux des objets
Encapsulation des données
consiste à faire une distinction entre l'interface de l'objet et son
implémentation.
Implémentation
Données Méthodes * Interface: décrit ce que fait
l'objet
Interface
Concepts fondamentaux des objets
Encapsulation des données (suite)
le principe de l'encapsulation est qu'on ne peut agir que sur les propriétés
publiques d'un objet.
Exemple de la nécessité de protéger les données:
supposons qu'on a une classe Température;
class Temperature:
attributs public: int TC; // température en ° Celsius
int TK; // température en Kelvin
supposons qu'on a une température TC=35 et TK=108 ; et que dans le code on a modifié
TC=40 (TK est toujours égale à 108) il n' y a plus de cohérence des données.
Le bon code serait:
class Temperature:
attributs private: int TC; méthode public: set_TC(t){ TC=t;
int TK;
TK=t+273;}
Concepts fondamentaux des objets
Communication par messages
les objets communiquent entre eux par des messages ( un objet demande un
service à un autre objet) pour résoudre un problème final .
Association simple
Objet 1 Message
Agrégation
Composition
Objet 3
...
Objet 2
Remarque: Les relations d'association, d'agrégation et de composition s'expriment
en insérant des variables membres dans une définition de classe.
Concepts fondamentaux des objets
Identité et classification
Consiste à regrouper les objets ayant le même comportement pour former un
même ensemble , appelé: classe ( c.à.d un nouveau type).
Un objet d'une classe s'appellera une instance de cette classe.
En C++ on déclare une classe par :
class Maclasse { ..........};
Exemple: class Livre {
char* titre; Une instance de cette classe par exemple:
Le livre:
char* auteur; Titre= ''Léon l'africain''
Auteur=''Amine Maâlouf''
void lire(){....};
};
Concepts fondamentaux des objets
Héritage
Consiste à définir une nouvelle classe à partir d'une classe existante à laquelle
on va ajouter de nouvelles propriétés ( attributs et/ou méthodes).
Concepts fondamentaux des objets
Polymorphisme
possibilité à divers objets de classes dérivées d'une même classe de répondre
au même message chacun à sa façon. i.e un même nom peut désigner des
propriétés de classes différentes.
Exemple: on peut invoquer la méthode ouvrir() quelque soit le type de la
porte automatique ou classique.
Généricité
consiste à définir des classes paramétrées. Une classe générique n'est pas
directement utilisable, mais permet de créer des classes dérivées qui
peuvent être manipulées.
Modularisation
les modules sont construits autour des classes.
Concepts fondamentaux des objets
La programmation basée sur les objets et leurs concepts fondamentaux
est dite la
Programmation Orientée Objets
(POO)
L'approche objet répond bien aux critères de qualités de production d'un
logiciel.
Le 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.
C++ versus C
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
...
Le Langage C++
La fonction principale :
La fonction main() est, comme en C, 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[]){...}
Les commentaires
Sur plusieurs lignes: /* .............comme en C....
...............*/
#include <iostream.h>
#include <iomanip.h> // attention a bien inclure cette librairie
int main() {
int i=1234;
float p=12.3456;
cout << "|" << setw(8) << setfill('*')
<< hex << i << "|" << endl << "|"
<< setw(6) << setprecision(4)
<< p << ''|'' << endl;
}
Le Langage C++
Les types de base
Héritage des mécanismes de bases du C (pointeurs inclus)
Attention : typage fort en C++!!
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
// réel à double précision
double pi = 3.141592653589793238462643;
char c=‘a’; // caractère
« Initialisation à la mode objet » :
int i(0) ;
Long l (123456789);
Le Langage C++
Type de base (2)
Le type d’une donnée détermine :
La place mémoire (sizeof())
Les opérations légales
Les bornes
Le Langage C++
Les constantes
Le qualificatif const peut être utilisé pour une expression constante:
const type_var var=cte;
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.
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.
Le Langage C++
Déclaration des fonctions
L'utilisation d'une fonction sans aucune déclaration ou définition au préalable
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
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.
Le 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!
Le 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)
Le 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).
Le Langage C++
Allocation dynamique
en C la manipulation dynamique de la mémoire se fait avec malloc et free
(<stdlib.h>). En C++, ces fonctions 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 & 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 & objets
Exemple
class Point
{
private:
int x;
Données membres ( ou attributs) privés
int y;
public:
void initialise(int,int); Méthodes public
void deplace(int,int);
void affiche();
} ;
Attention au point virgule après la définition d'une classe
Classes & objets
La mention d'accès par défaut dans une classe est private:
class Point
{
int x;
int y; // membres privés par défaut
public: // membres publiques
……};
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 & objets
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 & 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;
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 & 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.
Exemple:
class Point {
int x;
int y;
public:
Point(int,int); // constructeur
~Point(); // destructeur Dans cet exemple, la définition du destructeur sera de la forme:
……
Point::~Point() {… … }
};
Classes & 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.
Classes & objets
Exemple:
Considérons par exemple 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.
class Tab_entiers
{ /*------------------- définition du constructeur ---------------------*/
int nb; Tab_entiers::Tab_entiers(int n)
{
int * tab; nb = n;
tab = new int [nb];
public: }
/*------------------ définition du destructeur -----------------------*/
Tab_entiers(int); // constructeur
Tab_entiers::~Tab_entiers()
~Tab_entiers(); // destructeur {
delete tab;
…… }
};
Classes & objets
Exercice:
1) On désire munir la classe Point d'un constructeur qui permet de créer le point :
• (0,0) si aucun argument n'est fourni
• (abs,0) si on lui fournit abs comme seul argument
• (abs,ord) si on lui fournit les deux arguments abs et ord
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
Il faut noter que 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é (voir surcharge des opérateurs).
Classes & 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 & 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;
nb_obj++;
}
Classes & objets
Exemple:
#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.
Enfin, 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 & 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 & 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 & 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 & 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;
}
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 aussi dits membres statiques. Ils sont déclarés
avec l'attribut static, et existent même si aucun objet de la classe n'est crée.
• Ainsi 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 & objets
Exemple:
// Interface de la classe : POINT.H
// Corps de la classe : POINT.CPP
#ifndef POINT_H
#include "Point.h"
#define POINT_H // definition obligatoire du membre donné statique
int point::nb_obj;
#include <iostream.h> // utilisé dans affiche()
Point::Point(int abs, int ord)
class Point{ {
int x; x = abs; y = ord;
nb_obj++;
int y; }
static int nb_obj; Point::~Point()
{
public: nb_obj--;
Point(int = 0, int = 0); }
void Point::affiche()
~Point(); {
void affiche(); cout << "(" << x << "," << y << ")" << endl;
}
static void affiche_nbobj();
// definition de la fonction membre static
}; void Point::affiche_nbobj()
#endif {
cout<< ''le nombre d'objets est''<<nb_obj<<endl;
}
----
Classes & objets
Exemple (suite)
// 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 & 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.
Exemple:
class T { … ...
public:... // déclarations
type_a F(...); // fct membre ordinaire T u; // instance non constante
const T v; // instance constante
type_b G(…) const; // fct membre constante // appels
type_c K(const T); // fct avec argument constant u.F(…); // OK
v.F(…) ; // erreur: instance constante
}; u.G(…) ; // OK
v.G(…); // OK
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 & 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 & 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 & 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 & objets
Exemple
#include <iostream.h> // --------------- Définition des fonctions membres
//------------ Déclaration de la classe T::T(int n, int p)
{
class T{
i = n;
int i; pi = new int;
int *pi; *pi = p;
}
public: T::~T()
T( int = 0, int = 0); {
if(pi != NULL)
~T(); delete pi;
void affiche(); }
void T::affiche()
void modifier(int,int); {
}; cout << "(" << i << "," << *pi << ") --> " << pi <<
endl;
}
void T::modifier(int n, int p)
{
i = n ; *pi = p;
}
Classes & 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 & 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 & 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 & 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 & 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 & 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 & objets
Exemple :
class Point {int x,y; …};
Prototype de la fonction amie operator + :
Point operator +(Point,Point) ;
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 & objets
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
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 :
Héritage multiple :
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 le constructeur par défaut A NON : le constructeur synthétisé de B ne trouve
OK : le constructeur synthétisé de B appelle défini sans paramètres 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 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);
};
Appels Constructeurs
class A
{
private:
public:
};
class B : public A
{
private:
public:
B(T1 b1, T2 b2, T3 b3);
};
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
{
public:
int a1;
int a2; class B : private A int main()
{ {
}; public: B b;
using A::a1; b.a1 = 1; // OK
}; b.a2 = 1; // Illégal
return 0;
};
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
class A int x;
{ void B::f() Trois variables de
public: { même nom !!!
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
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
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
METHODE VIRTUELLE
Lorsqu’une méthode est virtuelle dans une classe de base, elle est
toujours virtuelle dans toutes les classes dérivées
Placer virtual avant le type de retour de la fonction
On répète virtual dans les classes dérivées pour la clarté (mais ce
n’est pas obligatoire)
METHODE VIRTUELLE (suite)
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
METHODE VIRTUELLE (suite)
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
METHODE VIRTUELLE(suite)
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
};
METHODE VIRTUELLE
SYNTAXE D’IMPLEMENTATION
bool A::IsA() const
{
return TRUE ;
}
A* pA = new A ;
A* pB = new B ;
if (pA->IsA())
cout << " Objet de classe A ";
if (pB->IsA())
cout << " Objet de classe B";
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éthodes virtuelles
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
METHODE 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
is tre a m o s tre a m
io s tre a m
fs tre 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
char c = 'a' ;
cout.put(c) ; // affiche le caractère c
Classe ISTREAM
cin est un objet de la classe istream
#include <iostream.h>
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) ;
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) { {
ofstream osf(nom_fic, ios::out);
Ecrire(''toto.txt'');
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) // Si la saisie a été correcte, on affecte à p
{ char c = '\0' ;
if (ok=true) { p.x = x ; p.y = y ; }
int x, y ; bool ok = true ;
entree >> c ; // saisie d’un caractère au clavier // Statut d’erreur du flot géré par
// un ensemble de bits d’un entier
if (c != '(') ok = false ;
// clear (activation de bits d’erreur)
else { entree >> x >> c ; // saisie de x (entier) // badbit (bit activé quand flot dans un état irrécupérable)
// et d’un autre caractère au clavier // rdstate () pur activer le bit badbit sans activer les autres
if (c != ',') ok = false ; else entree.clear (ios::badbit | entree.rdstate () ) ;
else { entree >> y >> c ; // même chose pour y
// on retourne le flux d'entrée
if (c != ')' ) ok = false ; } 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;
else return b ; Paramètre de type T
} (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) ;
Patrons de fonctions
Pas possible de créer un .o d’un patron de fonction
le mettre dans un fichier .h
Patrons (Templates)
main()
{
Point p1(2,5), p2(1,8),p3 ;
p3 = min(p1,p2) ;
}
Patrons (Templates)
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)
Tableau <int,4> t1 ;
Tableau <float,100> t2 ;
La gestion des exceptions
On lève une exception par l'instruction throw suivie d'une expression quelconque
(entier, double, chaîne de caractères, objet, ...).
Fichier MonException.h
class MonException {
public:
char *msg1, *msg2;
MonException (char *s1, char *s2);
};
int main()
{
try
{
// Demander a l'utilisateur d'entrer
void ouvrir(char* name) // un nom de fichier
{ ouvrir(filename);
FILE *f; // Utiliser le fichier ouvert pour
f = fopen(name, "r"); // lire des données
}
throw(1); catch (int n)
} {
if (n == 1)
std::cerr << "PB de fichier\n";
}
La gestion des exceptions
Interception des exceptions
A chaque type qui peut être utilisé pour lancer une exception, il faut prévoir un gestionnaire
(catch) adapté (si on veut attraper l’exception, bien sûr) :
void ouvrir(char* name)
{
FILE *f;
f = fopen(name, "r");
if(f==NULL) try {
throw("Pb de fichier"); ouvrir("input.txt");
}
} catch (const char *s) {
void ouvrir(char* name) std::cerr << s;
}
{
FILE *f;
f = fopen(name, "r");
if(f==NULL)
throw MonException("Probleme avec",name); try {
} ouvrir("input.txt");
}
catch (MonException &e) {
std::cerr << e.msg1<< e.msg2;
}
La gestion des exceptions
int main()
{
try
{
lire_donnees();
...
void lire_donnees()
}
{
catch(const char *s)
try
{
{
std::cerr << s;
ouvrir("in.txt"); void ouvrir(char* name)
}
... {
return 0;
} ...
}
catch (int n) throw("Pb de fichier");
{ }
// fait quelque chose
}}
La gestion des exceptions
Les exceptions ne sont pas seulement un bon moyen pour savoir quelle partie
du code a produit une erreur et pourquoi, elles permettent aussi de corriger
ces erreurs et de permettre au programme de continuer.
La gestion des exceptions
try
{
coeffAxial = tabCoeffAxial.interpole(machNumber);
}
catch (TableError &e)
{
if (e.x < (1.05*e.max_x))
coeffAxial = e.max_y;
else
{
std::cerr << "Sortie de table " << e.name
<< " au dela des tolerances " << std::endl;
throw(e);
}
}
La gestion des exceptions
Spécifier l'exception
Il est possible de spécifier les exceptions qu’une fonction ou une méthode a le droit
de lever :
class X {};
class A {
void f1(); // n’importe quelle type exception
void f2() throw(); // ne peut lever d’exception
void f3() throw(int); // peut lever des exceptions de type ‘int’
void f4() throw(int, double, X); // peut lever 3 types d’exceptions
};
void g1();
void g2() throw();
void g3() throw(int);
void g4() throw(int, double, X);
Remarque:
Durant l’exécution, si une exception d’un type interdit est levée,
le programme appelle une méthode spéciale « unexpected() »
que le programmeur peut par ailleurs modifier et utiliser à
sa guise par set_unexpected().
La gestion des exceptions
Fichier en-tête <stdexcept> bibliothèque standard fournissant des classes
d’exceptions
Plusieurs exceptions standard susceptibles d’être déclenchées par une fonction ou
un opérateur de la bibliothèque standard
Ex. classe Bad_alloc en cas d’échec d’allocation mémoire par new
vect::vect (int n) // Constructeur de la classe vect
{ adr = new int [nelem = n] ;}
int main ()
{ try { vect v(-3) ; }
catch (bad_alloc) // Si le new s’est mal passé
{ cout << "exception création vect avec un mauvaise nombre d'éléments " << endl ;
exit (-1) ;
}}
Classe exception ayant une méthode virtuelle what() affichant une chaîne de
caractères expliquant l’exception
int main ()
{
try { vect v(-3) ;}
catch (bad_alloc b)
{ // Appel de la méthode what() pour l’exception bad_alloc
cout << b.what() << endl ; exit (-1) ; // affichage: St9bad_alloc
}
}
La gestion des exceptions
class exception {
public:
exception () throw();
exception (const exception&) throw();
exception& operator= (const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
};
Classes dérivées de exception :
bad_alloc, bad_cast, bad_exception, bad_typeid …
La gestion des exceptions
Exceptions et constructeurs
• Il est parfaitement légal de lancer une exception dans un constructeur, ce
qui permettra de signaler une erreur lors de la construction d’un objet.
• Lorsqu’une exception est lancée à partir d’un constructeur, la construction
de l’objet échoue. Par suite, le destructeur pour cet objet ne sera pas appelé,
ce qui pose certains problèmes si l'objet est partiellement initialisé.
La gestion des exceptions
Exemple:
L'exemple suivant montre comment traiter le cas des objets partiellement initialisés,
lorsque la création de ces objets échoue.
Considérons une classe "etudiant" qui permet de manipuler les notes d'un étudiant.
Les notes de chaque étudiant seront stockées dans des tableaux d'entiers. On suppose
que le nombre de notes est variable et qu'il ne doit pas dépasser une certaine valeur
MAXNBNOTE.
On prévoit aussi dans cette classe une surcharge de l'opérateur [] qui permet l'accès
en lecture et en écriture à une note donnée
Pour gérer les différentes erreurs, on définit une classe de base "Erreur" et deux
autres classes DepMaxNbNote et InvalideIndice pour gérer respectivement le
dépassement de nombre de notes autorisé et le dépassement d'indice.
La gestion des exceptions
#include <iostream>
#include <string>
#define MAXNBNOTE 4
#define MAXSIZE 255
class DepMaxNbNote:public erreur{
using namespace std; public:
//DepMaxNbNote():erreur(){}
//------ classes exception
DepMaxNbNote(const char *s):erreur(s){}
class erreur{ void affiche(){
erreur::affiche();
protected:
cout << "Nombre max de notes est " << MAXNBNOTE << endl;
const char * raison; } };
public:
erreur():raison(0){}
erreur(const char* s):raison(s){}
class InvalideIndice:public erreur{
public:
virtual void affiche(){ InvalideIndice():erreur(){}
if (raison == NULL)
InvalideIndice(const char *s):erreur(s){}
void affiche(int i){
cout << "Erreur inconnu..." << endl; erreur::affiche();
else cout << raison << endl; cout << "Indice doit etre entre 0 et " << i << endl;
}
} }; };
La gestion des exceptions
Les containers
Les containers sont des objets qui permettent de stocker d’autres objets. Ils sont
décrits par des classes génériques représentant les structures de données logiques les
plus couramment utilisées : les listes, les tableaux, les ensembles... Ces classes sont
dotées de méthodes permettant de créer, de copier, de détruire ces containers, d’y
insérer, de rechercher ou de supprimer des éléments. La gestion de la mémoire, c’est-
à-dire l’allocation et la libération de la mémoire, est contrôlée directement par les
containers, ce qui facilite leur utilisation.
La STL (standard template library)
containers disponibles:
– vector : container implantant les tableaux, qui autorise les accès directs sur ses éléments.
Les opérations de mise à jour (insertion, suppression) sont réalisées en un temps constant à la
fin du container, et en un temps linéaire (dépendant du nombre d’éléments) aux autres
endroits.
– list : container implantant les listes doublement chaînées, dédié à la représentation
séquentielle de données. Les opérations de mise à jour sont effectuées en un temps constant à
n’importe quel endroit du container.
– deque : container similaire au vector, effectuant de plus les opérations de mise à jour en
début de container en un temps constant.
– set : container implantant les ensembles où les éléments ne peuvent être présents au plus
qu’en unseul exemplaire.
– multiset : container implantant les ensembles où les éléments peuvent être présents en
plusieurs exemplaires.
– map : container implantant des ensembles où un type de données appelé clé est associé aux
éléments à stocker. On ne peut associer qu’une seule valeur à une clé unique. On appelle aussi
ce type de container tableau associatif.
La STL (standard template library)
Exemple
#include <iostream>
#include <list>
int main()
{
list<int> lesEntiers;
// Ici, des instructions pour initialiser la liste des entiers
…
// Affichage des éléments contenus dans la liste
list<int>::iterator it;
for (it = lesEntiers.begin(); it != lesEntiers.end(); it++)
cout << *it << endl;
}
La STL (standard template library)
Iterator (suite)
Un itérateur :
pointe sur un élément d’un conteneur
peut être incrémenté par ++
peut être déréférencé par *
Il y a 3 types d'itérateurs :
unidirectionnel
bidirectionnel (--)
accès direct (it + i, it[i])
Remarque:
Itérateur de fin pointe juste après le dernier élément du conteneur
Si la liste vide : li.begin() possède la même valeur que li.end()
La STL (standard template library)
Les algorithmes
Les algorithmes sont des fonctions C++ génériques qui permettent
d’effectuer des opérations sur les containers.
Afin de pouvoir s’appliquer à plusieurs types de containers, les algorithmes
ne prennent pas de containers en arguments, mais des itérateurs qui
permettent de désigner une partie ou tout un container.
De ce fait, il est même possible d’utiliser ces algorithmes sur des objets qui
ne sont pas des containers.
Certains algorithmes ne nécessitent que des itérateurs de base (d’entrée ou
de sortie), et d’autres nécessitent des itérateurs plus évolués, comme la
fonction sort (effectuant un tri) qui nécessite un itérateur à accès direct.
La STL (standard template library)
Exemple
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
vector<int> tableauEntiers; // Crée un tableau d’entiers vide
int unEntier;
// Saisie des entiers
…
// Tri du tableau
sort(tableauEntiers.begin(), tableauEntiers.end());
// Affichage des éléments triés
vector<int>::iterator it;
for (it = tableauEntiers.begin(); it != tableauEntiers.end(); it++)
cout << *it ;
}