Programmation Cours C++ - ISGE - 2022-2023
Programmation Cours C++ - ISGE - 2022-2023
2
Organisation pratique
Cours magistraux et travaux dirigés: 20H
Travaux pratiques: 20H
Evaluation :
• 1 examen sur table
• 1 projet
3
Plan du cours
Introduction au C++
Syntaxes de base en C++
Programmation Orientée Objet C++
Gestion des Exceptions
4
Introduction au C++
5
Historique (1/2)
Le langage C a été mis au point en 1972, par Dennis Ritchie. Dès lors ce langage se fait une
réputation comme étant:
rapide
hautement portable
Champs application étendus (pilote de matériel jusqu'au logiciel de gestion, en passant par
les jeux)
Dans les années 80, le langage C++ est développé par Bjarne STROUSTRUP dans l’objectif
d’améliorer le langage C. Initialement ce nouveau langage a été nommé dans un premier temps «
C with classes » avant d’être nommé définitivement C++ en 1983.
6
7
Historique (2/2)
Principaux ajouts par rapport au C
Le type de données bool (booléen) ;
Les références
Les paramètres par défaut dans les fonctions
Les référentiels lexicaux (namespace) et l’opérateur de résolution « :: »
Les classes — POO
La surcharge des opérateurs
Les templates
La gestion d’exceptions
Le type de donnée string
8
QUELQUES CHIFFRES
9
QUELQUES CHIFFRES
Source: https://www.blogdumoderateur.com/classement-langages-informatiques-python-domine-php-top-10/
10
Caractéristiques du langage C++
C++ possède un certain nombre de caractéristiques qui ont largement contribué à son énorme succès :
C++ est compilé : La source est compilée
C++ est multiplateforme
C++ est orienté objet: C++ est orienté objet. Chaque fichier source contient la définition d'une ou
plusieurs classes qui sont utilisées les unes avec les autres pour former une application.
C++ est fortement typé: Toutes les variables sont typées et il n'existe pas de conversion automatique
qui risquerait une perte de données.
• Toute variable doit être déclarée avec un type
• Le compilateur vérifie que les utilisations des variables sont compatibles avec leur type
• Les types sont d'une part fournis par le langage, mais également par la définition des classes,
structure…
11
Avantages
Indépendant vis-à-vis de la plateforme (portabilité des fichiers sources)
langage orienté objet (réutilisation)
Rapide et puissant
Gestion de la mémoire dynamique
Gratuit et openSource
12
Inconvénients
syntaxe est très stricte
Utilisation de pointeurs
Absence de ramasse-miettes
13
Champs d’applications
Le C++ est utilisé pour la conception de plusieurs catégories d’applications:
Applications Desktop (client lourd)
Applications Embarquées
• les logiciels automobiles, les logiciels de contrôle de vol, le contrôle des fusées, les moteurs marins, le
contrôle des éoliennes, la tomographie par ordinateur et l’instrumentation scientifique
Gaming
14
Environnement
Ecrire un code C++ nécessite un ensemble de prérequis parmi lesquelles:
Installer un compilateur et/ou un EDI. EDI est l'abréviation de Environnement de
Développement Intégré. (Code::Blocks, Microsoft Visual Studio)
Créer un projet et écrire son premier programme
Enregistrez votre code source sous la forme d'un fichier .cpp
Compilez votre programme.
• Les utilisateurs de gcc en ligne de commande sous Linux pourront invoquer la commande g++ -c
addition.cpp && g++ -o addition addition.o
• Ceux qui travaillent avec un IDE devront utiliser le menu intitulé « Compiler », « Construire » ou
« Tout construire » de leur environnement pour rendre le programme exécutable.
• Un programme compilé sous Windows portera l'extension « .exe »
• Sous Linux, l'extension n'est pas nécessaire pour un exécutable.
15
Environnement
Testez votre programme
• Les utilisateurs de gcc sous Linux pourront entrer dans leur terminal :./addition
• Sous Windows, vous pourrez exécuter le programme en entrant
c:\repertoire\du\programme\addition.exe
16
Premier programme
{ #include <iostream>
#include <iostream> int main()
std::cout
En C++ <<comme
"Helloen World" << std::endl;
C, les lignes commençant par
Il#s’agit
sont de
desl’entête de la fonction
« directives main. En C++,».une
préprocesseurs Elles
using namespace std; } fonction se divise en deux parties principales. L’entête et le
s’adressent
corps à un programme appelé préprocesseur,
de la fonction.
int main() Le corps de la fonction
cpp (pour main. Ici,»)ilqui
« c preprocessor n’yprépare
a le code
En
qu’une C++,
seule
source c’est aussi leces
eninstruction,
traitant point
se d’entrée dupar
terminant
directives. programme.
un ; Il faut
{ juste retenir que main est la seule fonction qui doit
absolument apparaitre dans un programme. C’est une
Ici, enpeut
std::cout
convention. être vu
appelant comme l’écran,
#include, on dit auil préprocesseur
s’agit
cout << "Hello World" << endl; d’inclure le fichier iostream, deopérateur
la bibliothèque
du flux de sortie standard. << est un
int
opérant estsur
le type
standard unC++ de et
flux retour
dequi de laàfonction
contient
sortie sa main. int
les définitions
gauche et unepourpour
return 0; integer, c’est-à-dire que la fonction main, une fois terminée,
afficher
donnée
doit quelque
à lui transmettre,
retourner chose
une valeur à l’écran
àentière.
sa droite. via des « flux
Pour information, cette»
} valeur peut servir
ou « flots ». dans l’environnement appelant notre
« Hello Worldune
programme » est unedechaine
valeur bonne de caractère,
exécution ou un code erreur.
() ici vide,
std::endl il s’agit au
demande de la listededes
flux arguments
passer fournis lors de
à la ligne
l’appel de notre fonction.
suivante
17
#include <iostream> Exemple
using namespace std;
double somme(double , double ); /* Déclaration de la fonction somme */
int main() // point d'entrée de notre programme Voici l’exemple d’un programme un peu plus
{ complexe. On commence par déclarer une fonction
somme, sans la définir, c’est-à-dire sans écrire son
int a, b; code. On signifie seulement qu’il existe une telle
cout << "Donnez deux entiers" << endl; fonction, prenant deux réels en argument et renvoyant
un réel. On peut à présent l’utiliser dans le code qui
cin >> a >> b; suit la déclaration. On pourrait aussi, et on doit même
le faire pour plus de propreté, écrire cette partie dans
cout << a << " + " << b << "=" << somme(a, b) << endl;
un fichier header.
return 0;
}
// somme retourne la somme de a et b deux réels fournis en paramètres.
double somme(double a , double b) {
return a+b; }
18
Exemple : Utilisation des entêtes
#ifndef __SOMME_HH__
Un tel fichier header ressemblerait à celui-ci . On voit
#define __SOMME_HH__ apparaitre 3 nouvelles directives préprocesseurs ainsi que la
déclarations de la fonction somme. On remarquera aussi que
/* ce fichier NE CONTIENT PAS DE CODE, seulement des
Déclaration de la fonction somme déclarations.
Il s’agit simplement d’une protection, évitant lors de
*/ programme plus complexe, d’inclure deux fois un fichier
header. Le compilateur terminerait alors en erreur car il ne
double somme(double a, double b); veut pas de multiples définitions (surtout lorsqu’on définira
#endif des class).
En gros, si la constante __SOMME_HH__ n’est pas
définie, alors inclure le code ci après. Dans le code en
#ifndef __SOMME_HH__ question, on commence par définir une tel constante, et on
#define __SOMME_HH__ déclare notre fonction. Enfin, on ferme la condition #ifndef
par #endif
19
Syntaxes de base en C++
20
Notions élémentaires en
programmation
Programme source, code source: programme écrit dans un langage
Code machine: code compréhensible par la machine
Syntaxe d’un langage: manière de formuler une instruction correcte (la grammaire)
Erreur :(syntaxique ou erreur de compilation; erreur sémantique: erreur d’exécution)
21
Syntaxe du langage
Un programme C++ est constitué par un ensemble d’instructions.
Une instruction peut tenir sur plusieurs lignes;
le caractère de fin d’une instruction est “ ;” a = c + c ;
Commentaires
• Commentaire sur une ligne avec le symbole « // »
• Commentaire sur plusieurs lignes avec les symboles: « /* » (au début) et « */ » (à la fin)
22
Variables
Une variable est une entité dont la valeur peut changer au cours de l’exécution d’un programme.
Elle possède un nom (identificateur), un type et une valeur.
En C++, une variable est obligatoirement typée à sa déclaration
La déclaration d'une variable:
Un nom (identificateur),
Un type de données qu'elle peut contenir.
• type élémentaire encore appelé type primitif
• type objet
Une valeur initiale, qui peut éventuellement être indéfinie ;
La syntaxe générale est : <type> identificateur_variable ; Exemple: int a;
L’initialisation: consiste à affecter une valeur à une variable. Exemple: a=10;
23
Variables: identificateurs
Un identificateur est une suite de lettres (minuscules ou majuscules) et de chiffres. En plus des
lettres et chiffres, les caractères "$" , "_" , "μ" et les lettres accentuées sont autorisés pour
construire un identificateur C++.
Un identificateur ne doit pas commencer par un chiffre.
C++ fait une distinction entre minuscules et majuscules (sensible à la casse).
Les mots clés du langage C++ ne peuvent être utilisés comme identificateurs.
NB: il est déconseillé d’utiliser des identificateurs ayant des caractères accentués.
24
Variables: Mots clés
Une liste non exhaustive de mots clés:
25
Variables
Exemples:
string comment; // déclaration d’une variable
int jour, mois, annee ; // déclaration de plusieurs variables
Comment= ‘’test’’; // initialisation d’une variable
int a=4; // déclaration et affectation d’une valeur à une variable
26
Variables : portées
variables globales
La portée d’une variable peut varier. On dit qu’une variable est globale lorsque la portée de celle-ci
s’étend sur une portion de code ou de programme groupant plusieurs fonctions. On les utilise en
générale pour définir des constantes qui seront utilisées dans l’ensemble du programme.
variables locales
Ce sont les variables les plus couramment utilisées dans un programme, généralement déclarées
dans une fonction, et n’existent que dans celle-ci. Elles disparaissent (leur espace mémoire est
libéré) une fois que la fonction se termine
27
Types: types primitifs (1/2)
En C++, les types peuvent être de plusieurs catégories. Parmi lesquels les types primitifs (prédéfinis ou
élémentaires), et types référence, type objet.
Types primitifs:
Dans ce cas, la déclaration de la variable réserve la place mémoire pour stocker sa valeur (dépendant de
son type) Type Désignation Longueur
bool Valeur logique: true, false 1 bit
short Entier signé 16 bits
char Caractère unicode 16 bits
int Entier signé 16 bits
float Virgule flottante simple précision 32 bits
double Virgule flottante double précision 64 bits
long Entier long 64 bits
28
Références
Notion:
À côté des pointeurs, les références sont une autre manière de manipuler les
adresses des objets placés dans la mémoire. Une référence est un pointeur géré de
manière interne par la machine. Si T est un type donné, le type « référence sur T » se
note T&.
Exemple : int i; int & r = i;
Une valeur de type référence est une adresse, mais, hormis lors de son initialisation,
toute opération effectuée sur la référence agit sur l'objet référencé, non sur
l'adresse. Il en découle qu'il est obligatoire d'initialiser une référence lors de sa
création ;
NB:
• int &r = x; == > r est une référence sur un int
• p = &x; == >obtention d’adresse
29
Références
Utilité:
permettre de donner aux fonctions des paramètres modifiables, sans utiliser explicitement les pointeurs
Exemple: void permuter(int & a, int & b) {
int w = a;
Autre exemple:
a = b; b = w; void uneFonction(const unType & arg) {
} ... ici arg ne peut pas être modifié par la fonction (puisque const)
appel de la fonction permuter(t[i], u); }
30
Chaine de caractères
Manipulations de base
● Concaténation: on peut utiliser l’opérateur + pour concaténer deux chaînes de caractères :
Exemple:
string s1 = ”hello” ; String s2 = ”world” ; //declaration de deux variable de type string et affection
de valeur
string s3 = s1 + ” ” + s2 ; //concatenation de s1, s2. s3 vaut ”hello world”
cout << s3 << ” \n”; // affichage de s3 à l’écran
string str; // declaration de la variable str
cin >> str; // entrée clavier pour affecter de la valeur à str
getline(cin, str); // entrée clavier pour affecter de la valeur à str
cout << str<< ” \n”; // affichage de str à l’écran
31
Chaine de caractères: Exemple
#include <iostream>
using namespace std;
int main()
{
string a="Bonjour tout le monde";
string str;
cout << a <<endl; // affichage de la variable a à l’écran
getline(cin, str); //écrire une chaine de caractère dans la variable str
cout << str<<endl; // affichage de la variable a à l’écran
return 0;
}
32
Tableaux
Un tableau est une structure de données permettant de stocker une suite un nombre fixe
d’éléments de même nature (types). Ces éléments peuvent être des objets ou des primitifs.
Chaque élément est accessible grâce à un indice correspondant à sa position dans le tableau.
Une variable est déclarée comme un tableau dès lors que des crochets sont présents soit après son
type, soit après son identificateur. Les deux syntaxes suivantes sont acceptées pour déclarer un
tableau d’entiers (même si la première, non autorisée en C, est plus intuitive) :
Exemple:
int *tab = new int[10]; // un tableau de n int
float tab[10]; double tab_1 [2][3];
33
Opérateurs (1/2)
les Opérateurs d’affections : utilise pour assignation de valeur
34
Opérateurs (2/2)
Les opérateurs de
comparaison
35
Structure de contrôle (1/7)
Les structures de contrôle permettent d’exécuter un bloc d’instructions soit plusieurs fois
(instructions itératives) soit selon la valeur d’une expression (instructions conditionnelles ou de
choix multiple). Dans tous ces cas, un bloc d’instruction est
soit une instruction unique ;
soit une suite d’instructions commençant par une accolade ouvrante “{” et se terminant par
une accolade fermante “}”.
36
Structure de contrôle (2/8)
Instructions conditionnelles
Syntaxe :
if (<condition>) {
<bloc1>
}
else {
<bloc2>
}
NB: Quand la condition est respectée les instructions du bloc 1 sont exécutées au cas échéant celles du
bloc 2 sont exécutées
La partie else est facultative.
37
Structure de contrôle (3/7)
Instructions itératives
Les instruction itératives permettent d’exécuter plusieurs fois un bloc d’instructions, et ce, jusqu’à
ce qu’une condition donnée soit fausse. Les trois types d’instruction itératives sont les suivantes :
while, do while, for
38
Structure de contrôle (4/7)
Instructions itératives
Syntaxe :
Faire...TantQue... (do while) L’exécution de cette instruction Do {
suit les étapes suivantes : <bloc>
} while (<condition>);
1. le bloc est exécuté ;
2. la condition (qui doit renvoyer une valeur booléenne) est
évaluée. Si celle-ci est vraie on retourne à l’étape 1, sinon on
passe à l’étape 3;
3. la boucle est terminée et le programme continue son
exécution en interprétant les instruction suivant le bloc.
39
Structure de contrôle (5/7)
Instructions itératives
Pour...Faire (for): Cette boucle est constituée de trois parties :
(i) une initialisation (la déclaration de variables locales à la boucle est autorisée dans cette partie) ;
(ii) une condition d’arrêt ;
(iii) un ensemble d’instructions à exécuter après chaque itération (chacune de ces instructions est séparée par
une virgule).
Syntaxe : int tab [10];
for (<init>;<condition>;<instr_post_itération>)
for (int j=0; j>10; j++){
{
tab [i]=i+2;
<bloc>
} }
40
Structure de contrôle (6/7)
Instructions break et continue
Selon que (switch):L'instruction switch permet, comme l'instruction if, de déclencher des
traitements en fonction d'une condition (d'un test). D'un certain point de vue, cette instruction est
similaire à plusieurs if imbriqués mais est plus performante et sont plus recommandée.
switch (variable){ switch (variable){
case 1: case 1:
// instructions cout <<"Premier cas";
break; break;
case 2: case 2:
// instructions cout <<« Deuxieme cas";
break; break;
Default:
……..
cout <<« Troisieme cas";
Default: // optionnel break;
// instructions }
} 41
Structure de contrôle (7/7)
Instructions break et continue
Ces deux instructions sont le plus souvent utilisées dans d’une boucle, for (int i = 0, j = 0 ; i < 100 ; i++)
ou dans des boucles imbriquées. {
Break: est utilisée pour sortir immédiatement d’un bloc d’instructions if (i > sizeof(tab)) break ;
(sans traiter les instructions restantes dans ce bloc). Aucune nouvelle if (tab[i] == null) continue ;
itération du bloc ne s’exécute même si la condition d’arrêt (de la tab2[j] = tab[i];j++;
boucle) est toujours vraie. En cas de boucles imbriquées, break fait sortir }
de la boucle la plus interne
continue : utilisée pour arrêter l’exécution d’un bloc mais pas celle de la
boucle. Une nouvelle itération du bloc commence si la condition d’arrêt
(de la boucle) est toujours vraie.
42
Fonctions
Une fonction :
un « sous-programme » permettant d'effectuer des opérations répétitives.
• Une fois crée cette fonction peut être appelée autant de fois
• Allège le code, le rendre plus lisible.
Peut recevoir une ou plusieurs informations (appelées arguments, paramètres) desquelles elle peut
retourner ou pas des informations (résultats)
Type_retour nom_fonction (arguments) { // pour les fonctions void pas de valeur de retour
return valeur;}
45
Fonctions: passage par valeur
#include <iostream> Par défaut en c++, le passage des arguments à une
using namespace std; fonction se fait « par valeur ».
/*Cette fonction doit échanger la valeur des deux entiers C’est à dire que la valeur du paramètre est copiée en
passés en paramètres */ mémoire, et une modification sur la copie n’entraîne
void permuter (int, int); évidement pas la modification de l’original.
int main()
{
int a = 2, b = 3;
cout << "a : " << a << " b : " << b << endl;
permuter (a, b);
cout << "a : " << a << " b : " << b << endl;
}
void permuter (int a, int b){int tmp = a; a = b; b = tmp;
}
46
Fonctions: passage par adresse
Le passage de paramètres par adresse se fais par l’utilisation de pointeur
47
Fonctions: passage par référence
#include <iostream> Modifions la fonction permuter.Cette fois-ci le
using namespace std; programme a bien l’effet désiré
/*Cette fonction doit échanger la valeur des deux
entiers passés en paramètres */ La notation ‘int &’ signifie qu’on ne passe plus un
void permuter (int &, int &); entier par valeur mais par référence. Il n’y a
int main() donc plus copie de la valeur. On passe directement la
{ valeur elle-même.
int a = 2, b = 3;
cout << "a : " << a << " b : " << b << endl; La modification dans la fonction est donc répercutée
permuter (a, b); sur les paramètres transmis.
cout << "a : " << a << " b : " << b << endl;
} permuter (2, 3); // Impossible de changer les
void permuter (int & a, int & b){ int tmp = a; a = b; constantes
b = tmp; }
48
Fonctions: Surcharge
La surcharge est aussi appelé overloading ou surdéfinition. Elle consiste à créer,
fournir plusieurs définitions
On choisit l’une ou l’autre de ces définitions en fonction du contexte.
NB: la surcharge peut être aussi appliqué opérateurs vu précédemment comme +,
-, *, << …
49
Fonctions: Surcharge
#include <iostream> La fonction affiche est définie deux fois. Le nom ne
using namespace std; change pas, la valeur de retour ne change pas. Le type du
paramètre change.
void affiche (int a) Lorsque l’on appelle la fonction, le compilateur se base
{cout << "Hello ! L’entier est ! : " << a << endl; sur le type de l’argument pour choisir quelle fonction il
} va appeler. Dans certains cas, le compilateur n’arrive pas
void affiche (double a){ à faire un choix. Il se terminera alors en erreur.
cout << "Hello ! La valeur décimale est! : " << a << endl;
}
int main()
{
affiche (2); affiche (2.0);
return 0;
}
50
Fonctions en ligne
Le code exécutable d’une fonction est généré une fois par le compilateur.
Pour chaque appel de la fonction, le compilateur doit:
Sauvegarder l’état existant
Allouer de l’espace pour la valeur des arguments
Effectuer un branchement à la fonction (édition de liens)
Recopier la valeur de retour
Restaurer l’état courant
Retourner au programme qui fait appel à la fonction
51
Fonctions en ligne
Le code exécutable d’une fonction est généré une fois par le compilateur.
Pour chaque appel de la fonction, le compilateur doit:
Dans le cas de petites fonctions, ces différentes instructions peuvent représenter un pourcentage
important de temps d’exécution.
La spécification inline dans l’appel d’une fonction permet de gagner en efficacité, lorsque la taille
du code devient importante.
La présence du mot clé inline permet de considérer la fonction comme un bloc d’instructions au
sein du programme.
Le mécanisme de gestion de l’appel de la fonction et de retour au programme n’existe plus.
Le mot clé inline permet une économie de temps.
La quantité de mémoire est plus importante et augmente avec le nombre d’appels
52
Fonctions en ligne
La présence du mot clé inline permet de considérer la fonction comme un bloc d’instructions au
sein du programme.
Le mécanisme de gestion de l’appel de la fonction et de retour au programme n’existe plus.
Le mot clé inline permet une économie de temps.
La quantité de mémoire est plus importante et augmente avec le nombre d’appels
Exemple: NB: La portée d'une fonction en ligne est réduite au fichier où
inline int abs(int x) { la fonction est définie. Par conséquent, de telles fonctions sont
généralement écrites dans des fichiers en-tête (fichiers « .h »),
return x >= 0 ? x : -x; qui doivent être inclus dans tous les fichiers comportant des
appels de ces fonctions
}
53
Fonction: Valeurs par défaut des
arguments
Les paramètres formels d'une fonction peuvent avoir des valeurs par défaut.
void trier(void *table, int nbr, int taille = sizeof(void *), bool croissant = true);
Lors de l'appel d'une telle fonction, les paramètres effectifs correspondants peuvent alors être
omis (ainsi que les virgules correspondantes), les paramètres formels seront initialisés avec les
valeurs par défaut.
Exemples :
trier(t, n, sizeof(int), false);
trier(t, n, sizeof(int)); // croissant = true
trier(t, n); // taille = sizeof(void *), croissant = true
54
Rappel: Structures
Jusqu’à présent, nous avons rencontré les tableaux qui étaient un regroupement de données de
même type. Il peut être utile de grouper des données de types différents et de les regrouper dans
une même entité. En C, il existait déjà un tel mécanisme connu sous le nom de structure.
C++ conserve cette possibilité, tout en lui ajoutant de nombreuses possibilités. Ainsi, nous allons
créer de nouveaux types de données, plus complexes, à partir des types que nous connaissons
déjà.
55
Structures
Une structure se déclare grâce au mot clé struct suivi du nom de la structure. La structure
Personne devient alors un type de donnée.
Ce type est un regroupement d’un entier et de deux double. Dans la fonction main, après avoir
inclus notre fichier header au début de notre code, nous pouvons déclarer une variable de type
Personne. Cette variable s’appellera p1.
Les valeurs de différents types contenus dans la structure sont appelés des champs. Pour accéder
aux champs d’une variable dont le type est une structure, on utilisera l’opérateur point « . » suivi
du nom du champ. Ainsi p1.age est de type entier, et on peut lui associer une valeur pour
l’afficher ensuite.
struct Personne
Personne toto = {35, 78, 168.5};
{
NamedPoint pt[3] = {{0,0, "Origine"}, {1,0, "X"}, {0,1, "Y"}}; int age;double poids;
double taille;};
56
Structures: Déclaration
#ifndef __STRUCT_HH__ #include <iostream> Dans cet exemple nous commençons par
#include "struct.hh" déclarer une structure Personne dans un fichier
#define __STRUCT_HH__ struct.hh
using namespace std;
struct Personne int main() Ce n’est pas obligatoire, nous aurions pu
{ { déclarer cette structure dans le fichier contenant
la fonction main, avant de l’utiliser, mais c’est
int age; Personne p1; une bonne habitude qui deviendra de plus en
double poids; p1.age = 35; plus importante au fur et à mesure que nous
double taille; p1.poids = 55.7; avancerons dans ce cours.
}; p1.taille = 160.5;
cout << p1.age << " "
#endif
<< p1.poids << " "
<< p1.taille << endl;
}
57
Structures: structures imbriquées
Créer une structure revient à créer un nouveau type. On
peut donc utiliser ce nouveau type comme champ
d’une autre structure comme dans l’exemple ci contre.
Ici encore, on notera le type des objets sur lesquels on
travaille :
v est de type Valeur.
v.x est un double
v.date est de type Date
v.date.jour est un entier
58
Entrées/sorties (1/2)
Les entrées sorties font référence à l'utilisation des flux standard d'entrée-sortie. En C les fonctions printf
et scanf sont habituellement utilisées à cet effet.
En C++, un programme qui utilise les flux standard d'entrée-sortie doit comporter la directive:
#include <iostream.h> ou
#include <iostream> //lorsqu’on utilise compilateur récent tout en suivant de près les recommandations de la norme
Les flux d'entrée-sortie sont représentés dans les programmes par les trois variables, prédéclarées et
préinitialisées, suivantes :
cin, le flux standard d'entrée (l'équivalent du stdin de C), qui est habituellement associé au clavier
cout, le flux standard de sortie (l'équivalent du stdout de C), qui est habituellement associé à l'écran
cerr, le flux standard pour la sortie des messages d'erreur (l'équivalent du stderr de C),
59
Entrées/sorties (2/2)
Ces variables sont utilisés avec les opérateurs << appelé opérateur d'injection (« injection » de
données dans un flux de sortie) et >>, appelé opérateur d'extraction (« extraction » de données
d'un flux d'entrée).
syntaxe d'une injection de donnée sur la sortie standard cout
cout << expression à écrire ;
cout << expression << expression << expression;
int main() {
double x;
int n;
cout << "Donne x et n : ";
cin >> x >> n;
cout << x << "^" << n << " = " << puissance(x, n) << "\n";
}
60
Programmation Orientée Objet
61
Avantages de la programmation
orientée objet
Les style objet favorisent:
la programmation modulaire
l'abstraction
la spécialisation
L'objectif est de produire du code
facile à développer, à maintenir, à faire évoluer,
réutilisable, tout ou en partie, sans avoir besoin de le dupliquer
62
Principes fondamentaux
Modularité: vise à repartir les opérations (fonctionnalités) d’une application sur plusieurs
modules, afin que le cycle de vie de chaque module soit indépendant des autres
Abstraction: vise à représenter des objets du monde réel en objet dans un programme
informatique. Cela consiste essentiellement à extraire des variables pertinentes, attachées aux
objets que l'on souhaite manipuler, et à les placer dans un modèle informatique convenable.
Elle consiste aussi à:
séparer la définition (d'un type, d'une classe, d'une méthode) de l'implémentation
Permettre d'identifier un modèle commun à plusieurs composants
Donner la possibilité de partager ce modèle commun via le mécanisme d'héritage
Encapsulation: mécanisme permettant de définir des niveaux de visibilité des éléments de la
classe. Ces niveaux de visibilité définissent les droits d'accès aux données selon que l'on y
accède par une méthode de la classe elle-même, d'une classe héritière, ou bien d'une classe
quelconque. Cela permet de s’assurer que l’utilisateur ne contourne pas l’interface qui lui est
destinée.
63
Principes fondamentaux
Héritage: Cela signifie qu’une classe B hérite de la classe A. Autrement dit, la classe B hérite
des attributs et méthodes de la classe A. On peut alors appeler Les méthodes contenues dans la
classe A par la classe B dès lors qu’une instance de la classe B est créée. Cela fait énormément
gagner en temps.
Polymorphisme : Il permet au développeur d’utiliser une méthode ou un attribut selon plusieurs
manières, en fonction de son besoin. Une même méthode peut, par exemple, être utilisée sur des
entités différentes. La méthode du même nom produira des effets différents selon son contexte
d’utilisation.
64
POO avec C++
Objet en programmation = objet dans le monde réel
Objet = propriétés (attributs) + actions (méthodes)
65
Structure de données (objet simple)
Un concept utilisé pour créer des types composés dont plusieurs variables de différents types
(attributs).
Une structure peut contenir des fonctions pour manipuler les attributs et effectuer différentes
opérations.
La création d’une structure de données se fait par l’utilisation du mot clé struct
66
Structure de données (objet simple)
On peut déclarer les noms des objets (variables) à utiliser au moment de la définition de l’objet
lui-même.
Syntaxe: Exemple:
struct Personne
struct nom_type
{
{
string nom;
type nom_variable;
string prenom;
type nom_variable;
string date_naissance;
type nom_variable;
int numero_social;
…
} etudiant, enseignant, administrateur,
} nom1, nom2, nom3 ;
agent_securite,*liste_etudiant ;
67
Structure :Exemple de définition
struct Personne #include <iostream>
{ #include “personne.h”
string nom; using namespace std;
string prenom; int main()
string date_naissance; {
float taille; // déclaration variable statique
Personne etudiant; //déclaration variable dynamique
void affichage()
Personne* enseignant;
{ // accéder aux éléments avec point
// afficher des informations etudiant.nom = “nom quelconque”;
} cout <<etudiant.afficher() <<endl;
void changerTaille (float num)
{ }
taille = num;
}
};
68
Classe
On reprend l’exemple précédent // structure pour les étudiants // structure pour les enseignants
de l’étudiant, l’enseignant struct Etudiant struct Enseignant
{ {
Toutes les catégories précédentes string nom; string nom;
des personnes partagent quelques string prenom; string prenom;
propriétés communes. (e.g. nom, string date_naissance; string date_naissance;
prénom, date de naissance, etc.). float taille; float taille;
… int grade;
Chaque catégorie a quelques }; string diplome;
propriétés uniques …
Redondance };
Solution idéale
L’utilisation des objets plus évolués (classes) qui
permettent de bien structurer le code et faciliter la
conception.
69
Classe
Classe vs structure:
Encapsulation
Héritage
Polymorphisme
Interface
70
Classe: Définition
Une classe est une moule, un patron qui permet de créer des objets en série sur le même
modèle. On peut se représenter une classe comme le schéma de construction ainsi que la liste des
fonctionnalités d’un ensemble d’objets.
71
Classe : Résumé
Une classe
Catégorie d'objets
Moule à partir duquel il est possible de créer des objets
Une classe est un type dans un langage orienté objet
Une classe contient :
Des attributs ou données ou membres données
Membres d’une classe
Des méthodes ou fonctions membres
72
Classe: Syntaxe de création
Pour créer une classe on utilise le mot clé
Exemple: class:
SYNTAXE class Personne
class nom_classe Les termes public, private, protected désignent
{
{/* déclaration des membres privés */ la visibilité des attributs et des méthodes
private:
private://facultatif public: membres (attrivbuts/méthodes) visibles
string nom; de partout
type variable; string prenom; private: visible uniquement dans la classe
type variable; string date_naissance; protected: visible uniquement des classe fille
/* déclaration des membres public: (notion d’héritage)
publiques */ void marcher( )
public: { // écrire un code }
type fonction( ) { }
type fonction( ) { } Remarque: Une classe est une structure qui
int dormir( ) comporte des membres publics (accessibles de
…
};
{ // écrire un code } l'extérieur) et privés (accessibles uniquement à
}; partir des fonctions membres)
73
Classe: Encapsulation des membres
L’encapsulation sert pour:
donner des droits d’accès aux membres (méthodes et attributs) des classes .
protéger les attributs contre la modification de l’extérieur.
Il existe trois modificateurs d’accès (mot clés):
public = membres accessibles même par d’autres objets
private = membres accessibles par la classe seulement
protected = membres accessibles par la classe et ses enfants (classe fille, classe dérivée)
74
Classe: structuration
En C++, il y a trois manières de créer le contenu (implémenter) des classes:
Déclarer et définir les membres à l’intérieur de la classe.
Déclarer les membres à l’intérieur et les définir à l’extérieur de la classe.
Déclarer les membres à l’intérieur et les définir dans un autre fichier.
75
Classe: structuration
1) Déclarer et définir les membres à 2) Déclarer les membres à l’intérieur et les Pour définir le contenu des
l’intérieur de la classe définir à l’extérieur de la classe méthodes (fonctions) en dehors
class Personne class Personne de la classe on met le nom de
{ { la classe suffixé par :: entre le
string nom;
string nom; string prenom; type et le nom de la méthode.
string prenom; string date_naissance;
string date_naissance; void marcher( );
void marcher( ) int dormir( ); :: operateur de résolution
{ // écrire un code }; de portée
} void Personne :: marcher( ) Les deux structurations sont
int dormir( ) {// écrire un code déconseillées. Priorisez la
{// écrire un code } troisième
} int Personne :: dormir( )
}; {// écrire un code
}
76
Classe: structuration
3) Déclarer les membres à l’intérieur et les définir dans un autre Méthode conseillée et professionnelle
fichier.
#ifndef __PERSONNE_H__ #include ’’personne.h’’
#define __PERSONNE_H__ Dans le fichier source (implémentation),
class Personne on inclut le fichier header avec la directive
{ void Personne :: marcher( )
string nom; #include.
{// écrire un code
string prenom; }
string date_naissance;
public: int Personne :: dormir( )
void marcher( ); {// écrire un code
int dormir( );
}; }
#endif
personne.h personne.cpp
fichier entête ou fichier fichier source
d’interface Extension: .cpp
Extension: .h de préférence le même nom du header
77
Classe: Méthodes
une méthode est une « fonction », un sous programme que l’on peut utiliser dans une autre méthode
d’une classe, dans une classe ou dans un objet selon le modificateur d’accès (visibilité).
Chaque méthode à deux parties:
Sa signature (type de retour, nom, types des paramètres) ou prototype utilisé pour sa déclaration
Sa définition (Son code), qui est constituée de blocs imbriqués
Les méthodes contenues dans une classe peuvent être groupées en plusieurs catégories dont les
principales sont les suivantes:
Constructeurs
Accesseurs
Mutateurs
Destructeurs
autres méthodes
78
Classe: Catégories de méthodes
Constructeurs
Méthodes permettant de créer une instance(objet) et d’initialiser les attributs de cet instance au
moment de son instanciation (new).
Il y a réservation d’espace mémoire à ce moment seulement
Son identificateur (nom de la methode) porte le même nom que la classe
N’a aucun type de retour dans sa définition mais retourne une instance de la classe.
• Définition : Personne(string nom, string prenom ){…}
• Appel : Personne *p = new Personne(‘’SAWADOGO’’, ‘’Ali’’); //appel le constructeur
Personne p1(‘’SAWADOGO’’, ‘’Ali’’);
Si aucun constructeur n’est écrit, il en existe un constructeur par défaut qui ne fait rien et les
attributs sont initialisés avec leur valeur par défaut (selon le type).
79
Classe: Catégories de méthodes
Constructeurs
Un constructeur peut comporter un nombre quelconque d'arguments, éventuellement aucun.
Par définition, un constructeur ne renvoie pas de valeur, et aucun type ne figure devant son
identificateur.
Les constructeurs peuvent être publics ou privés mais en pratique ils sont publics.
Peut être surchargé (définitions de plusieurs constructeurs)
80
Classe: Catégories de méthodes
Destructeur
Méthode qui permet, lors de la fin de la portée d’un objet, de remettre au système les ressources
utilisées par un objet.
Cette méthode est appelée automatiquement lorsque la dernière référence à une instance n’y fait plus
référence. Par exemple x = null; S’il n’y a aucune autre référence sur l’instance sur laquelle x
pointait.
Les ressources utilisées peuvent être une imprimante, de la mémoire, etc. Cela pourrait être aussi de
terminer une autre application
81
Classe: Catégories de méthodes
Destructeur
Le destructeur porte le même nom de la classe en respectant le majuscule et le minuscule et
doit être préfixé du caractère ~.
Le destructeur est une fonction membre appelée automatiquement au moment de la
destruction d'un objet.
Pour un objet, la destruction de l'objet a lieu quand on quitte le bloc ou la fonction où il a
été déclaré.
Le constructeur et le destructeur peuvent être publics ou privés. En pratique, ils sont
publics.
82
Classe: Catégories de méthodes
EXEMPLE Point::Point() //constructeur sans argument
class Point{ {this-> x=0; this->y =0;
private : }
int x; Point:: Point (int a) //constructeur avec un argument
int y; {
public : x=a; y=a;
Point() ; //constructeur sans argument }
Point (int ); //constructeur avec un argument Point:: ~Point () {cout << "objet point détruit";}
~ Point() ;
void affiche(); //fonction membre affiche
sans argument int main () {
void affiche (String ) ; //fonction membre //creation de deux instances avec les constructeurs
affiche avec un argument Point *p1=new Point(); Point p2 (10);
} delete p1; //appel du destructeur
}
83
Classe: Catégories de méthodes
Mutateurs ou setters
◦ Méthodes permettant de modifier le contenu (valeur) des attributs d’une classe.
84
Classe: Catégories de méthodes
Accesseurs ou getters
◦ Méthodes qui permettent d’obtenir le contenu des attributs (généralement privés) d’une
classe.
85
Classe: Catégories de méthodes
Exemple avec setter et getter Point::Point()
{ this-> x=0; this->y =0;
class Point{ }
private :
Point:: Point (int a)
int x;
{ x=a; y=a;
int y;
}
public :
//setter ou encore mutateur
Point() ; //constructeur sans argument
Point (int ); //constructeur avec un argument Point::setX (int a){
~ Point() ; this-> x=a;}
void affiche(); //fonction membre affiche //getter ou encore accesseur
sans argument int Point::getX (int a){
void setX(int); return x;
int getX (); }
}; Point:: ~Point () {cout << "objet point détruit";}
86
Classe: Auto-référence (this)
Chaque classe possède un pointeur « caché », noté this. Lors de la création d’un objet, ce pointeur
désigne l’emplacement mémoire où l’objet est stocké.
Par conséquent, dans la déclaration d’une méthode référencer un attribut, par exemple, x ou this-> x
revient au même... d’un point de vue langage C++.
En effet, d’un point de vue génie logiciel on évitera à tout prix la seconde notation qui alourdie
inutilement la lecture de vos programmes
87
Classe: Autres propriétés des
méthodes
Surcharge(overloading, surdéfinition): consiste à fournir plusieurs définitions pour la même méthode
Le choix de la fonction est basé sur le type et le nombre des arguments.
toutes les méthodes y compris le constructeur peuvent être surdéfinies
Caractéristiques de la surcharge de méthodes:
Leur nom est le même
Le nombre ou le type de leurs paramètres et/ou le type de la valeur de retour peuvent être différents.
Objectif: Exemple : int puissance (int,int)
double puissance (double, int)
88
Classe: Autres propriétés des
méthodes
Surdéfinition (surcharge)
class Point{
private :
int x;
int y;
public :
Point() ; //constructeur sans argument
Point (int ); //constructeur avec un argument
Point (int , int ); //constructeur avec deux arguments
89
Classe: Les membres statiques
Déclarés avec le mot clé static, les membres (attributs et méthodes) statiques sont liés à la classe et non à
une instance particulière (un objet)
Attributs: sa valeur n'est pas propre à un objet mais à la classe (le champ lui même, et sa valeur, est la même
pour tous les objets de la classe)
• On y accède à partir du nom de la classe ou de la référence à n'importe quel objet de la classe
• Exemple: static nom; //declaration d’un attribut static
Méthodes: son code ne dépend pas d'un objet de la classe et peut être exécuté même si aucun objet existe
Tout code utilisé dans les membres statiques ne peut pas faire référence à l'instance courante (this)
Les membres statiques (static) sont dits membres de classe
Ils sont définis sur la classe et non sur les objets
Les membres non statiques (ou d'instance) ne peuvent exister sans un objet
90
Classe: Les membres statiques
Exemple:
class Circle {
int x, y;
unsigned int radius; int i = Circle::count;
méthode de classe
static int count;
public:
static const int MAX = 10;
static const double PI = 3.1415926535;
static int getCount(); méthode de classe
};
91
Classe: Fonction amie
Une fonction amie d’une classe est une fonction qui, sans être membre de la classe, a néanmoins
accès à toutes les données et fonctions-membres de cette classe, qu’elles soient publiques,
protégées ou privées.
Une telle fonction amie doit être déclarée à l’intérieur de la déclaration de la classe. S’il s’agit
d’une fonction libre (i.e. extérieure à toute classe) :
S’il s’agit d’une fonction-membre d’une autre classe :
class A class B; // informe le compilateur qu’il existe une classe
nommée B
{
class A
friend type nomFonction();
{
// fonction libre amie de la
friend type B:: nomFonction(); // fonction-
classe A membre de la classe B, amie de la classe A
public: public:
..... .....
private: private:
..... .....
}; };
92
Classe: Classes amies
Lorsque toutes les fonctions-membres d’une classe B sont amies d’une classe A, on dit que la
classe B est amie de A. Au lieu de déclarer dans la classe A chaque fonction-membre de B comme
amie, on écrit plus simplement :
class B; // informe le compilateur qu’il existe une classe nommée B
class A
{
friend class B; // la classe B est déclarée amie de la classe A
public:
.....
private:
.....
};
Remarque: Il ne faut pas abuser de la relation d’amitié, car elle constitue une entorse au principe
d’encapsulation.
93
Objet
Un objet est une définition de caractéristiques propres à un élément particulier. Il s’agit d’un
élément concret qui contient les propriété de sa classe.
Un objet est une instance d’une classe. Cela signifie qu'un objet est la matérialisation concrète d'une
classe (tout comme la maison est la matérialisation concrète du plan de la maison).
Le mécanisme de création des objets à partir d’une classe s’appelle l’instanciation.
un objet est comme une « variable » conforme à un type, qui est une classe.
Les opérations (méthodes) de l’objet utilisent les valeurs des attributs de l’objet.
Un objet possède une identité qui permet de le distinguer des autres objets. On accède à un objet via
une référence qui pointe sur l’objet.
Ainsi, dans l’instruction « Personne p ; », p est déclarée comme étant une référence sur un objet de
type Personne.
94
Objet
95
Objet
Un objet n'a de « réalité » qu'à l'exécution du programme.
L'instruction new sert à créer un objet (instanciation). Cette instruction réserve l'espace mémoire
nécessaire, initialise les attributs de l'objet créé et renvoie son adresse.
Caractérisé par :
son comportement (les méthodes les méthodes pouvant lui être appliquées), des services que
l'objet peut nous rendre : que peut-on faire avec cet objet?
• Méthodes
son état (les valeurs de ses attributs) : comment réagit l’objet quand on applique ces méthodes?
• Attributs (Champs)
son identité : comment distinguer les objets qui ont le même état et le même comportement?
• Identifiant, identité (référence stockée dans la ou les variables référençant l’objet)
96
Objet: Utilisations
Pour pouvoir utiliser un objet il faut :
Définir un nom pour cet objet : on utilise une déclaration sous la forme : NomDeClasse *nomDObjet;
Créer l'objet associé à ce nom par le mot clé new : nomDObjet = new NomDeClasse(paramètres);
On demande ensuite à cet objet de faire quelque chose en invoquant l'une de ces méthodes publiques :
nomDObjet.nomDeMethode(paramètres);
On peut aussi accéder aux attributs publics de cet objet par leur nom : nomDObjet.nomAttribut
97
Objet
class Personne {
Les étapes de création d’un objet:
private :
• Déclarer une variable du type de
string nom;
la classe
double taille;
• Créer une instance d’objet (new) public :
• Manipuler l’objet double imc ();
Manipulation de l’objet ( Forme void setNom (string);
générale) };
• nomVariable.attribut: réfère à un #include <iostream>
attribut de l’objet using namespace std;
int main () { Déclaration
• nomVariable.méthode( ): réfère Personne * p_1;
à une méthode de l’objet p_1=new Personne (); Création d’une instance
p_1.setNom("Aziz");
cout<<”imc”<< p_1.imc() <<”\n”; Manipulation de l’instanc
}}
98
Objet: Accès aux attributs et
méthodes
Avec le point « . » sur une référence à un objet:
p_1.x, p_1.imc();
Le compilateur regarde le type déclaré de la variable (ici p_1) et vérifie que le membre (ici x ou
imc) existe.
Le compilateur vérifie également les droits d'accessibilité
Un champ et une méthode peuvent avoir le même nom
« this » représente l'instance courante
99
Surcharge d’opérateurs
En C++, on peut surcharger la plupart des opérateurs usuels du langage, c’est-à-dire les reprogrammer pour
que, dans un certain contexte, ils fassent autre chose que ce qu’ils font d’habitude.
Cette technique permet de réaliser des opérations mathématiques intelligentes sur les classes
100
Surcharge d’opérateurs: Exemple
#ifndef __PERSONNE_H__ #include ’’personne.h’’ #include <iostream.h>
#define __PERSONNE_H__ #include ’’personne.h’’
class Personne void Personne :: setNom(string s ) using namespace std;
{ { nom=s;
string nom; } ostream &operator<<(ostream& os,
string prenom; string Personne :: getNom() Personne& p){
string date_naissance; {return nom; os << " ( " << p.getNom() << " " <<
} p.getPrenom() << ")";
public:
void setNom(string); void Personne :: setPrenom(string s )
{ prenom=s; int main () {
void setPrenom(string); Personne p; p.setNom("Saw " );
string getNom(); }
string Personne :: getPrenom() p.setPrenom(« Ali " );
string getPrenom();
}; {return prenom;
} cout<<p;
#endif }
101
Héritage
Le concept d’héritage permet à partir d’une classe de base, de créer une ou plusieurs classes
dérivées (encore appelée classes filles) . La classe fille hérite des propriétés de la classe de
base (encore appelée classe mère) et possède ses propres propriétés.
Plusieurs classes peuvent être dérivées d’une classe de base, et une classe dérivée peut devenir
une classe de base pour une autre classe. La notion d’héritage est un outil de spécialisation des
classes.
L’héritage multiple permet de dériver une classe à partir de plusieurs classes de base.
102
Héritage: Principe
Définir les propriétés communes dans la classe supérieure
Définir les propriétés spécifiques dans la sous-classe
Regrouper les objets le plus possible
Les objets d’une sous-classe sont aussi des objets de la super-classe
103
Héritage: syntaxe
Déclaration d’une classe de base point Déclaration d’une classe dérivée pointcolor int main() {
/* déclaration de la classe point */ class pointcolor: public point pointcolor p; p.initialise (10,20);
class point { p.color(5); p.affiche();
{ short couleur;
p.deplace(2,4); p.affiche();
/* déclaration des membres privés */ public:
}
private: void coloration (short cl);
int x; void affichecolor();
void initialisecolor(int, int, short); Déclaration d’une nouvelle
int y; classe pointcolor qui
/* déclaration des membres publics */ }; possède les attributs de la
void pointcolor::affichecolor(){affiche();
public: cout<<“ et la couleur est ”<<couleur<<“\n” ; }; classe point et qui permet
void initialise (int, int); en outre d’attribuer une
void deplace (int, int); void pointcolor::initialisecolor (int abs, int ord, short couleur à un point.
void affiche (); cl){initialise(abs, ord); couleur = cl; };
}; void pointcolor:: coloration (short cl){
couleur = cl};
104
Héritage: syntaxe
La déclaration class pointcolor: public point spécifie que pointcolor est une classe dérivée de
la classe de base point.
Le mot clé public signifie que les membres publics de la classe de base point seront des
membres publics de la classe dérivée pointcolor.
La déclaration des objets de type pointcolor se fait par l’instruction :
pointcolor p,q;
Chaque objet de type pointcolor peut alors faire appel :
aux méthodes publiques de pointcolor ;
aux méthodes publiques de la classe de base point.
105
Héritage simple: syntaxe
Une méthode d’une classe dérivée n’a pas accès aux membres privés de sa classe de
base.
Une méthode d’une classe dérivée a accès aux membres publics de sa classe de base.
Pour avoir accès aux données membres de la classe de base, l’utilisation de nouvelles
fonctions membres est nécessaire (les données membres étant privées) :
Définition d’une nouvelle fonction membre affichecolor de la classe pointcolor qui
permet d’afficher les coordonnées d’un point et sa couleur.
Définition d’une nouvelle fonction membre initialisecolor de la classe pointcolor qui
permet d’attribuer des valeurs aux données membres x, y et couleur à partir de trois
valeurs reçues en argument.
106
Héritage simple : Redéfinition des
fonctions membres
Il est possible de redéfinir les fonctions membres au sein de la classe dérivée. L’opérateur de
résolution de portée permet de faire la distinction avec les fonctions membres de la classe de base.
107
Héritage simple : Redéfinition des
fonctions membres
void pointcolor::affiche()
#include <iostream>
{point::affiche(); //appel de affiche de la classe point
#include “point.h”
cout<<“ et la couleur est ”<<couleur<<“\n” ;
using namespace std;
};
/* déclaration et définition de la classe pointcolor */
void pointcolor::initialise(int abs, int ord, short cl)
class pointcolor: public point
{
{
point::initialise( abs, ord);
short couleur;
couleur = cl;
public:
};
void coloration (short cl);
int main()
void affiche(); //redéfinition de affiche
{
void initialise(int, int, short); //redéfinition de initialise
pointcolor p; p.initialise (10,20,5); p.affiche();
};
p.point::affiche(); //appel de la fonction affiche de la classe point
p.deplace(2,4); p.affiche();
p.coloration(2); p.affiche();
}
108
Héritage simple : Redéfinition des
fonctions membres
Il est possible de redéfinir les fonctions membres au sein de la classe dérivée. L’opérateur de
résolution de portée permet de faire la distinction avec les fonctions membres de la classe de
base.
De la même manière que pour les fonctions membres, il est possible de redéfinir les données
membres au sein de la classe dérivée.
pointcolor p;
p.point::x permet d’accéder à la donnée membre x héritée de la classe point.
Redéfinition et surdéfinition :
109
Héritage simple : Redéfinition des
fonctions membres
Lorsqu’une fonction membre est définie dans une classe, elle masque toutes les
fonctions membres de même nom dans la classe de base (et dans les classes
ascendantes).
La recherche d’une fonction (surdéfinie ou non) se fait dans une seule portée : celle
de la classe concernée, celle de la classe de base (ou d’une classe ascendante) mais
pas dans plusieurs classes à la fois.
Quelque soient les arguments et le type de la valeur de retour d’une fonction
membre privée dans une classe de base, son emploi dans une classe dérivée sera
interdit.
Remarque: Si la signature de la méthode définie dans la classe dérivée (fille) n’est
pas exactement le même que celle de la classe mère, il s’agit d’une surcharge
110
Héritage simple : constructeurs et
destructeurs
Pour créer un objet de type pointcolor, il faut au préalable créer un objet de type
point (appel du constructeur de la classe point), et compléter la création de l’objet de
type point avec les attributs spécifiques à l’objet de type pointcolor (appel du
constructeur de la classe pointcolor).
Le mécanisme est pris en charge par le compilateur sans qu’il ne soit nécessaire de
prévoir l’appel du constructeur de la classe de base dans le constructeur de la classe
dérivée.
De la même manière, lors de la destruction d’un objet de type pointcolor, il y’a
automatiquement un appel du destructeur de la classe de dérivée pointcolor puis
celui de la classe de base point. Les destructeurs sont appelés dans l’ordre inverse des
constructeurs.
111
Héritage simple : constructeurs et
destructeurs
Pour créer un objet de type pointcolor, il faut au préalable créer un objet de type
point (appel du constructeur de la classe point), et compléter la création de l’objet de
type point avec les attributs spécifiques à l’objet de type pointcolor (appel du
constructeur de la classe pointcolor).
Le mécanisme est pris en charge par le compilateur sans qu’il ne soit nécessaire de
prévoir l’appel du constructeur de la classe de base dans le constructeur de la classe
dérivée.
De la même manière, lors de la destruction d’un objet de type pointcolor, il y’a
automatiquement un appel du destructeur de la classe de dérivée pointcolor puis
celui de la classe de base point. Les destructeurs sont appelés dans l’ordre inverse
des constructeurs.
112
Héritage simple : constructeurs et
destructeurs
Lorsque le constructeur de la classe de base nécessite des arguments, il faut
spécifier dans la définition du constructeur de la classe dérivée, les informations
qui doivent être transmises au constructeur de la classe de base.
113
Héritage simple : constructeurs et
destructeurs
#include <iostream> /* déclaration et définition de la classe pointcolor */
using namespace std; class pointcolor: public point
class point {short couleur;
{ public:
private: pointcolor (int,int,short); //constructeur pointcolor
int x; ~pointcolor (); //destructeur point
int y; };
public: pointcolor::pointcolor(int abs=0,int ord=0,short
point (int abs=0, int ord=0); //constructeur point cl=1):point(abs,ord){
~point (); //destructeur point cout<<“++constructeur pointcolor :”<<abs<<“ et ”<<ord<<“
}; et”<<cl<<“\n”;
point :: point (int abs=0, int ord=0) { couleur=cl;
cout<<“++constructeur point :”<<abs<<“ et ”<<ord<<“\n”;} }
point :: ~point (){ pointcolor::~pointcolor(){cout<<“--destructeur pointcolor
cout<<“--destructeur point :”<<abs<<“ et ”<<ord<<“\n”;} de couleur :”<<couleur<<“\n”;}
114
Héritage simple : constructeurs et
destructeurs
Si la classe de base ne comporte pas de constructeur (ou de destructeur), aucun
problème ne se pose.
Si la classe dérivée ne possède pas de constructeur, et que la classe de base en possède
une, il ne sera pas possible de transmettre des informations au constructeur de la classe
de base : dans ce cas, le constructeur de la classe de base ne doit pas prendre
d’arguments.
pointcolor::pointcolor(int abs=0,int ord=0,short cl=1):point(abs,ord)
Les informations abs et ord sont transmises au constructeur de la classe de base point.
L’instruction de déclaration :
pointcolor p(10,15,3);
correspond à l’appel des constructeurs point p(10,15); et pointcolor p(10,15,3);
115
Héritage multiple: notion
C++ permet de faire un héritage multiple contrairement aux autres langages de programmation
Après les deux points ( : ), on met les noms des classes (avec les modificateurs) parentes séparés
par des virgules
class Enfant : public Parent1 , public Parent2 , public Parent3 {
};
116
Héritage : contrôle d’accès
mode de statut du membre dans statut du membre dans la classe
dérivation la classe de base dérivée
private private inaccessible
protected private
public private
protected private inaccessible
protected protected
public protected
public private inaccessible
protected protected
public public
117
Classe abstraite
Une classe abstraite contient au moins une méthode abstraite
Une méthode abstraite (purement) est une méthode non implémentée dans la classe parente et
implémentée et redéfinie différemment par les sous-classes.
Objectifs:
Traiter des classes liées de manière uniforme sans prendre en considération leurs détails
Imposer une spécification d’implémentation des sous-classes (classes dérivées)
118
Classe abstraite
Une méthode purement abstraite est précédée par le mot clé virtual dans la classe parente et on
lui affecte 0
La redéfinition est précédée par le mot clé override dans les sous-classes et a la même signature
Le mot clé final peut être ajouter pour spécifier que la méthode ne peut plus être redéfinie
class Engin
{ class Vehicule:Engin
float m_speed , m_weight; {
Engin(); int m_nb_wheels;
~Engin(); override void move() { //code }
virtual void move() = 0; override void stop() { //code }
virtual void stop() = 0; };
};
119
Interface
Une interface est un cas particulier des classes abstraites et caractérisée par:
Pas de variables et constructeurs
Toutes les méthodes sont abstraites
class Vehicule : Engin
class Boat : Engin
{
class Engin {
protected:
{ protected:
int m_posX, m_posY;
public: int m_nb_motors;
bool m_state;
virtual void move() = 0; public:
public:
virtual void stop() = 0; override void move() {}
override void move() {}
virtual void open() = 0; override void stop() {}
override void stop() {}
virtual void close() = 0; override void open() {}
override void open() {}
}; override void close() {}
override void close() {}
};
};
120
Classe string
Un objet de type String contient à un instant donné, une suite formée de caractères
quelconques. Sa taille peut évoluer dynamiquement au cours du programme.
La notion de caractère de fin de chaîne n’existe. Le caractère NULL (\0) peut même apparaître
au sein de la chaîne à plusieurs reprises.
L’accès aux éléments existants peut se faire avec l’opérateur [] ou avec la fonction membre at.
Le premier caractère correspond à l’indice 0.
Un objet de type String possède une taille courante fournie par la fonction size (). La classe
String possède aussi une fonction membre length qui joue le même rôle que la fonction size().
La fonction capacity fournit le nombre maximum de caractères que l’emplacement mémoire
qui contient l’objet de type String peut contenir.
Les itérateurs à accès direct iterator et reverse_iterator et les valeur particulières begin(),
end(), rbegin() et rend() permettent de manipuler la chaîne.
121
Construction d’un objet de type
string
La classe String possède plusieurs constructeurs dont certains correspondent aux constructeurs d’un
vecteur.
string ch1; /* chaîne vide : ch1.size()==0*/
string ch2(10,’*’); /* chaîne de dix caractères ‘*’: ch2.size()==10*/
string ch3(5,’\0’); /* chaîne de cinq caractères de code nul : ch3.size()==5*/
Certains constructeurs permettent d’initialiser une chaîne lors de sa construction :
string message1 (“bonjour”); /* chaîne de longueur 7 */
string message1 = “bonjour”;
char *adr = (“bonsoir”); /* chaîne de longueur 5 */
string message2 (adr);
string message2 = adr;
122
Construction d’un objet de type
string
À partir du constructeur par recopie :
string s1;
string s2 (s1);
string s2 = s1;
À partir d’une séquence de caractères (l une chaîne de type list<char>) :
/* recopie des caractères de la liste l dans la chaîne ch1 */
string ch1 (l.begin(),l.end());
123
Opérations sur un objet de type
string
La fonction d’affectation, les fonctions assign et swap, ainsi que les fonctions de comparaisons
lexicographiques permettent de manipuler les objets de type String
Remarque :
Il est impossible de lire une chaîne comportant un espace blanc (espace ou fin de ligne).
Il n’y a pas de restriction sur la longueur de la chaîne.
124
String: Concatenation
L’opérateur + permet la concaténation :
de deux objets de type String ;
d’un objet de type String avec une chaîne usuelle ou avec un caractère.
string ch1 (“bon”); /*ch1.length()==3 */
string ch2 (“jour”); /*ch2.length()==4 */
string ch3; /*ch3.length()==0 */
ch3=ch1+ch2; /*ch3.length()==7 et ch3 == “bonjour” */
ch3=ch1+‘ ’; /*ch3.length()==4 */
ch3+=+ch2; /*ch3.length()==8 et ch3 “bon jour” */
ch3+=“monsieur”; /*ch3.length()==17 et ch3 “bon jour monsieur” */
Cependant, il n’est pas possible de concaténer deux chaînes usuelles ou une chaîne usuelle et un
caractère.
125
Recherche dans une chaîne
Les fonctions de recherche permettent de retrouver :
la première ou la dernière occurrence d’une chaîne ou d’un caractère donnés ;
la première ou la dernière occurrence d’un caractère appartenant à une suite de caractères
donnés.
la première ou la dernière occurrence d’un caractère n’appartenant pas à une suite de
caractères donnés.
Lorsque la chaîne ou le caractère est trouvé, la fonction renvoie en retour l’indice correspondant
au premier caractère concerné.
Lorsque la recherche n’aboutit pas, la valeur de retour est un indice en dehors des limites
permises pour la chaîne.
126
Recherche dans une chaîne
Recherche d’une chaîne ou d’un caractère La fonction find permet de rechercher dans une chaîne
donnée, la première occurrence :
d’une autre chaîne (sous-chaîne)
d’un caractère
La recherche commence au début de la chaîne par défaut, mais il est possible de la faire débuter à
partir d’un indice donné.
La fonction rfind permet de rechercher la dernière occurrence d’une chaîne ou d’un caractère.
127
Recherche dans une chaîne
Recherche d’un caractère présent ou absent d’une suite
La fonction find_first_of recherche la première occurrence de l’un des caractères d’une autre
chaîne.
La fonction find_last_of recherche la dernière occurrence de l’un des caractères d’une autre
chaîne.
La fonction find_first_not_of recherche la première occurrence d’un caractère n’appartenant
pas à une autre chaîne.
La fonction find_last_not_of recherche la dernière occurrence d’un caractère n’appartenant
pas à une autre chaîne.
128
Insertions, suppression et
remplacement
Insertion
La fonction insert permet d’insérer :
À une position donnée, définie par un indice :
Une autre chaîne de type String ou une partie de chaîne définie par un indice de début et une
éventuelle longueur.
Une chaîne usuelle de type char ou une partie de chaîne usuelle définie par une longueur.
Un certain nombre de fois un caractère donné ;
À une position donnée définie par un itérateur :
Une séquence d’éléments de type char, définie par un itérateur de début et un itérateur de fin ;
Une ou plusieurs fois un caractère donné.
129
Insertions, suppression et
remplacement
Suppression
La fonction erase permet de supprimer :
Une partie d’une chaîne, définie soit par un itérateur de début et un itérateur de fin, soit par un
indice de début et une longueur.
Un caractère donné défini par un itérateur de début.
130
Insertions, suppression et
remplacement
Remplacement
La fonction replace permet de remplacer une partie d’une chaîne définie, soit par un indice et une
longueur, soit par un intervalle d’itérateur par :
Une autre chaîne de type String.
Une partie d’une autre chaîne définie par un indice de début et, éventuellement, une longueur ;
Une chaîne usuelle (de type char) ou une partie de longueur donnée ;
Un certain nombre de fois un caractère donné.
131