Vous êtes sur la page 1sur 135

Programmation en

C++

Par Dr Eugène Pamba Capo-chichi


Le 05/12/2023
En guise d’introduction…

Système d’exploitation ? Compilation ? langage informatique ?


Algorithme ? Programmation Orienté Objet etc…
C’est la base de ce qui va suivre…
Définitions
.

1 Système d’exploitation : un système d'exploitation, ou OS pour


Operating System, définit un ensemble de programmes chargé
d'établir une relation entre les différentes ressources
matérielles, les applications et l'utilisateur

2 Compilation : elle consiste à traduire le contenu d’un fichier source en


Langage machine, en faisant appel à un programme appelé compilateur.

3 Algorithme : c’est une série d'instructions et d'opérations réalisées, dans


un ordre précis, sur des données afin de produire un résultat, et souvent
résoudre un problème plus ou moins complexe.
Introduction au Langage C++
Le langage C++ est un langage de Programmation Orienté Objet.

1 Initialement développé en 1980 par Bjarne Stroustrup à partir du


Langage de C
• Les premières versions étaient baptisées “C avec classes”.
• Le nom C++ prononcé ”See ++” en anglais, autement dit “voir plus loin”,
reflète le caractère évolutif du C++ par rapport au langage C puisque
“++” est l’opérateur d’incrementation.

2 Avantages
• Augmentation de la productivité
• Programmes plus souples, de meilleure qualité et facile à maintenir,
quelque soit la taille du projet.

3 Objectifs de la Programmation Orientée Objet (POO)


• Fournir une solution à un problème, et il existe plusieurs façons de
parvenir à ce résultat.
• Dans la POO, vous n’allez pas fonctionner en termes de données et de
fonctions pour les manipuler mais en termes d’objets.
• Les objets sont des entités avec des propriétés et des caractéristiques
bien spécifiques.
Les apports de la Programmation
Orientée Objet
Classe : c’est une généralisation de la notion de type. Elle définit la structure d’un
élément en regroupant ses données et ses méthodes.
Objet : Un objet est une instance d’une classe.
Héritage : permet de définir une nouvelle classe à partir d’une classe existante en y
ajoutant des Nouvelles données et des Nouvelles méthodes. L’Héritage facilite la
reutilisation.
Polymorphisme : Une classe dérivée peut redefinir certaines méthodes de sa classe
de base.
Le programme “Hello World”
#include <iostream>
using namespace std;
int main() {
cout << "!!!Hello World!!!" << endl;
return 0;
}
Le programme “Hello World”
#include <iostream>
using namespace std;
int main() {
cout << "!!!Hello World!!!" << endl;
// l’absence de using namespace std aurait obligé d’écrire std::cout
return 0;
}

main : l’entête main signifie que c’est un programme principal. Le programme principal n’est rien d’autre
qu’une fonction à laquelle on impose le nom main. Les programmes C++ commençent par exécuter la
fonction main.
#include : directives qui seront prises en compte avant la compilation par un programme qu’on appelle
préprocesseur parfois appelé précompilateur.
iostream : représente les flux d’entrée et de sortie. IO signifie Input et Output. Iostream contient les
déclaration relatives aux flux, en particulier cout et cin et aux opérateurs << et >>.
#include iostream : cette directive demande d’introduire avant compilation des instructions situées dans
le fichier iostream.
Using namespace: l’instruction using permet d’indiquer qu’on se place dans l’espace de noms std et
permet de régler les problèmes que peuvent poser l’utilisation des mêmes noms par différentes
bibliothèques
cout: c’est l’abréviation de character output stream.
Return 0: la fonction main est appelé par le système donc le zéro retourné par la fonction n’est pas
utilisé. Par contre sur certains systèmes comme Unix/Linux, le zéro indique que le programme s’est
terminé avec succès.
Création d’un programme C++(1/2)
q Les étapes
1. Edition d’un fichier source (avec comme extension .cpp) à l’aide d’un
éditeur de programme. Cette phase s’appelle édition de programme.
2. Traduction du programme source (proc.cpp) en langage machine (binaire)
qui aura pour extension .o (proc.o). Cette phase s’appelle compilation
3. Liaison des fichiers objets (.o) qui peuvent être des fichiers de la
bibliothèque standard, des fichiers utilisateurs implémentant des fonctions
utilisées dans proc.o. Cette phase s’appelle édition de liens.
4. Création de l’exécutable du programme. C’est l’exécutable qui permet de
lancer le programme.
La particularité d’un Environnement de développement intégré (IDE en anglais) est de gérer de
manière transparente ces étapes.

q La compilation en C++ se fait en deux étapes :


1. Traitement par le préprocesseur qui exécute les directives qui le concernent
(celle qui commence par le caractère #) et produit en résultat un fichier
source en C++ pur.
2. Compilation proprement dire du fichier fournit par le préprocesseur en
langage machine.
Création d’un programme C++(2/2)

qLes erreurs
1. Les erreurs détectés par le compilateur sont des erreurs de
compilation.
2. Celles que trouvent l’éditeur de liens sont des erreurs de liaisons ou
d’éditions de liens.
3. Les erreurs qui passent inaperçues sont des erreurs d’exécution ou
de logique. Les erreurs d’exécution sont plus difficiles à corriger par
rapport aux erreurs de liaisons qui elles-mêmes sont plus difficiles à
corriger que les erreurs de compilation.

qExercice : écrire un programme qui affiche la recette


pour faire du manioc ou quelque chose que vous aimez
bien.
Programme Recette Riz
#include <iostream>
using namespace std;

int main(){
cout << " *Recette pour réaliser du Riz*" << endl;
cout << "" << endl;
cout << "Premierement il faut préparer le matériel adequat: \nLe riz - La marmite - huile - sel -
eau" << endl;
cout << "Commencer par rincez abondamment le riz pour enlever toutes sortes de saleté." <<
endl;
cout << "Ensuite, mettre la marmite au feu avec un peu d'huile à l'intérieur." << endl;
cout << "Ajouter le riz et du sel, puis remuer pendant au moins 10 minutes." << endl;
cout << "Ajouter de 1 cm au dessus du riz" << endl;
cout << "Laissez l'eau tarir et remuer la marmite afin de faire passé le riz du dessus vers le
dessous" << endl;
cout << "Mettre le rechaud à feu doux pour la suite." << endl;
cout << "Attender environs 15 minutes et c'est bon!" << endl;
cout << "" << endl;
cout << " BON APPETIT" << endl;
return 0;
}
Qu’est ce qu’une variable ?
Les variables (1/2)

qLes emplacements mémoire dans lesquels sont stockés


des données s’appellent des objets.
qPour accéder à un objet, il faut un nom et ce nom
s’appelle une variable.
qUne variable possède un type spécifique.
qLes données que l’on placent dans les variables
s’appellent des valeurs.
qUne instruction qui définit une variable est une
définition.
Les variables (2/2)

qUne variable est caractérisée par :


ü Un nom : composé de lettres ou de chiffres
commençant par une lettre ;
ü un type précisant la nature de cette variable (nombre
entier, chaines de caractères etc.) ;
ü une valeur qui peut être modifié `a tout instant.

q Durant l’exécution d’un programme, à toute variable est


attachée une adresse : nombre entier qui indique où se
trouve stockée en mémoire la valeur de cette variable.
Les types numériques (1/2)
q en#ers, par taille mémoire croissante :
• char, stocké sur un octet ; valeurs : de −27 à 27 − 1 (−128 à 127),
• short, stock é sur 2 octets ; valeurs : de −215 à 215 − 1 (−32768 à
32767),
• long, stocké sur 4 octets ; valeurs : de −231 à 231 − 1,
• int, coïncide avec short ou long, selon l’installaFon.
• Long long introduit par C++ 11 et représenté sur 64 bits
minimum.
q réels, par taille mémoire croissante :
• float, stocké sur 4 octets ; précision : environ 7 chiffres,
• double, stocké sur 8 octets ; précision : environ 15 chiffres,
• long double, stocké sur 10 octets ; précision : environ 18
chiffres.
Les types numériques (2/2)
üUn bit est réservé pour représenter le signe du nombre (0 pour un
nombre positif et 1 pour un nombre négatif)
ü Dans le choix du type des variables entières, il est important de
prendre en compte les valeurs minimales et maximales que vous
envisagez stocker afin d’optimiser la mémoire utilisée

Ø On trouve parfois le mot unsigned précédant le nom d’un type


entier (on parle alors d’entier non signé ; un tel entier est toujours
positif).
Ø L’opérateur sizeof(un_type) donne l’espace mémoire occupé par
une une valeur de type.
Les types caractères et booléen
q char : caractères usuels entre apostrophes. Il existe une
correspondance entre les caractères et les entiers selon la table
d’ASCII. Exemple : ’A’ (= 65), ’a’ (= 97), ’0’ (= 48), ’ ’ (= 32).
Il existe également des caractères spéciaux ou codes de mise en
forme :
ü ’\n’ : retour à la ligne ;
ü ’\r’ : retour chariot ;
ü ’\v’ : tabulation verticale ;
ü ’\t’ : tabulation horizontale ;
ü ’\a’ : signal sonore.
q string : chaînes de caractères entre guillemets, pour les
affichages. Exemple : string bye = "Au revoir " ;
q bool : les valeurs possibles pour une variable de type bool sont
true et false.
Exemple

#include <iostream>
using namespace std;
int main() {
cout << "Entrer ton prénom et ton age" << endl;
string bye = "A bientôt" ;
string prenom ;
int age ;
cin >> prenom ;
cin >> age ;
cout << "Hello" << prenom << "(" << age << ")" << endl;
cout << bye ;
return 0;
}
//Le cin est sensible au type entré.
//Tester cin >> age en entrant une chaine de caractères.
Déclaration et affectation (1/3)
q Toute variable doit être déclarée avant d’être uFlisée.
q Forme de la déclaraFon : <type> <variable>
ü <type> : nom de type ou une classe
ü < variable> : une ou plusieurs variables séparées par une
virgule. Exemple : int a, b, c ; //déclaraNon de trois enNers.
q Il est possible d’a9ribuer une valeur à une variable
(ini1alisa1on) lors de sa déclara1on. Exemple : int a, b =-1, c ;
q Forme de l’affecta=on : <variable> = <valeur> (Exemple : int a = 2);
La valeur peut être une expression évaluée.
q Exemple : L’expression i+=1 équivaut à i = i+1;
L’expression x+=y équivaut à x = x+y;
Déclaration et affectation (2/3)
q Notation parenthésée : int i(5) équivaut à int i = 5;
q Il est possible de déclarer des constantes, c’est-à-dire des
variables dont on ne peut pas modifier les valeurs. Par Exemple : const
double PI = 3.14159265358979323846 ;
q Depuis C++11, il existe un mot-clé constexpr qui sert à désigner
une variable constante dont la valeur est connue lors de la
compilation :
Exemple : const int n = 6 ; constexpr int p = 3 * n + 2 ; // p sera calculé à la compilation
q Le mot clé auto introduit par C++ permet de définir
automatiquement le type d’une variable, soit à partir d’une
expression d’initialisation, soit à partir d’une autre expression.
Exemple : auto n = 12 ; // 12 est de type int, donc n sera de type int
q Le mot clé decltype permet de déclarer qu’une variable est de
même type qu’une autre variable.
Exemple 1 : long n1 = 10 ; decltype (n1) n2 = 20 ; // n2 sera du type de n1, donc long
Exemple 2 (à partir d’une expression) : int n ; decltype (2*n+1) p ; // p sera du type de
l’expression 2*n+1, donc int
Déclaration et affectation (3/3)
Notez qu’il existe des styles de programmation assez opposés, entre
lesquels nous ne chercherons pas à trancher ici, à savoir :
1. déclarer systématiquement toutes les variables en début de la
fonction concernée ;
2. placer la déclaration d’une variable le plus près possible de son
utilisation.
Conversion de types
q Une expression d’affection peut provoquer une conversion de
types
Exemple 1: int i = 3, float x; x=i ; x a la valeur 3.0 (C’est une conversion d’un
entier vers un réel).
Exemple 2: int i; float x = 5.6 ; i =x; i a la valeur 5. (C’est une conversion d’un
réel vers un entier et seule la partie entière est conservée).

q Une conversion de types peut être forcée à l’aide de l’opérateur


de cast ().
Exemple 3: float x = 7,3 ; int i = (int)x. (i a pour valeur 7 car l’expression (int)x
est de type int et sa valeur est la partie entière de x).
q Les conversions d’un type numérique vers un autre type
numérique sont qualifiées par static_cast.
Exemple 4: int n =10, p=3; la conversion se note : static_cast<double> (n/p);
Les opérateurs (1/3)
qOpérateurs unaires
Opérateur Action
- Valeur négative
~ Complément à un
++ Incrémentation
-- Décrémentation
! Négation

qOpérateurs arithmé<ques

Opérateur Action
+ Addition
- Soustraction
* Multiplication
/ Division
% Modulo (reste de la division entière)
Les opérateurs (2/3)
qOpérateurs logiques
Opérateur Action
& Et Logique (test1 & test 2 est vrai si test1 est vrai et test2 est vrai)
| Ou Logique
^ Ou exclusif
&& Et logique (test1 && test 2, Idem test1 & test 2, mais test2 n’est évalué
que si test1 est vrai)
|| Ou Logique

q Toute opérande de valeur nulle correspond à faux. Toute valeur


non nulle (et donc pas seulement la valeur 1) correspond à vrai.

q Les deux opérateurs && et || jouissent en C++ d’une propriété


intéressante connue souvent sous le nom de « court-circuit » :
leur second opérande (celle qui figure à droite de l’opérateur)
n’est évalué que si la connaissance de sa valeur est indispensable
pour décider si l’expression correspondante est vraie ou fausse.
Les opérateurs (3/3)
qOpérateurs bit à bit
Opérateur Action
& Et Binaire
| Ou Binaire
^ Ou exclusif
>> Décalage vers la droite (division par 2)
26 >>1 donne 13
<< Décalage vers la gauche (multiplication par 2) 26 >>1 donne 52
qOpérateurs de relationnels ou de comparaison
Opérateur Action
== Egalité
!= Inégalité
< Inférieur
> Supérieur
<= Inférieur ou égal
>= supérieur ou égal
Préincrémentation & Postincrémentation
q int i = 0 ;
q Quel est le résultat ?
ü int n = ++i – 5 ;
ü cout << n << endl ;
q Quel est le résultat ?
ü int n = i++ - 5 ;
ü cout << n << endl ;
Préincrémentation & Postincrémentation
q int i = 0 ;
q Quel est le résultat ?
ü int n = ++i – 5 ; => -4
ü cout << n << endl ;
q Quel est le résultat ?
ü int n = i++ - 5 ;
ü cout << n << endl ; => -5

q ++ opérateur de préincrémenta=on : ++i ;


q ++ opérateur de pos=ncrémenta=on : i++ ;
Un peu d’entrainement…

qExercices
1. Ecrire un programme qui calcule la somme entre des nombres.
2. Ecrire un programme qui calcule la moyenne entre des nombres.
3. Ecrire un programme qui calcule le périmètre et la surface d’un
cercle.
Les Structures de contrôle
q Permettent la modification de l’ordre d’exécution des
instructions dans votre code
q Deux types de structures sont disponibles :
ü Les instructions de décision
Elles aiguillent l’exécution du code en fonction des valeurs que
pourra prendre une expression de test
ü Les instructions de boucle
Elles font exécuter une portion de code un certain nombre de
fois
v Jusqu’à ce qu’une condition soit remplie
v Tant qu’une condition est remplie
Instruction if (1/2)
if (expression) if (expression)
instruction_1 instruction_1
else
instruction_2

q expression : expression quelconque (éventuellement convertie


implicitement en bool) ; depuis C++11, il pourra s’agir
également d’une « expression déclaration ».

q instruction_1 et instruction_2 sont instructions quelconques,


c’est-à-dire :
• simple (terminée par un point-virgule) ;
• bloc ;
• instruction structurée.
Instruction if (2/2)
expression ? instrucFon_1 : instrucFon_2 if (expression)
instruc-on_1
else
instruc-on_2

q Imbrica=ons de If : des instruc=ons if peuvent être imbriquées


q L’instruc=ons if peut dorénavant comporter une ini=alisa=on
sous la forme d’une expression ou d’une déclara=on:
if (int i=1 ; a < b ) { i++ ; cout << .... ; }
else { i-- ; cout << .... ; }
// ici, i n’existe plus
// La portée de i est limitée à celle de l’instruc>on.
Entrainement…
q Exercice 1 : Quel est le résultat ?
ü z = (x=y) ? a : b ; //y =5 ; a=6, b=7.
q Exercice 2
ü Ecrire un programme qui demande à un utilisateur un nombre
et qui affiche s’il est pair ou pas.
q Exercice 3
ü Ecrire un programme qui prend la couleur d’un feu et quand le
feu est vert, nous invite à passer et quand il est rouge à
s’arrêter.
Entrainement…
q Exercice 1 : Quel est le résultat ?
ü z = (x=y) ? a : b ; //y =5 ; a=6, b=7. résultat : => z= 6.
ü x=y est une affectation qui sera toujours vraie donc z=a.
q Exercice 2
ü Ecrire un programme qui demande à un utilisateur un nombre
et qui affiche s’il est pair ou pas.
q Exercice 3
ü Ecrire un programme qui prend la couleur d’un feu et quand le
feu est vert, nous invite à passer et quand il est rouge à
s’arrêter.
Instruction switch
switch (expression)
{ case constante_1 : [ suite_d’instructions_1; break; ]
case constante_2 : [ suite_d’instructions_2; break; ]
..............
case constante_n : [ suite_d’instructions_n; break; ]
[ default : suite_d’instructions ]
}
Instructions do … while, while et for
do
instrucNon ;
while (expression)

while (expression)
InstrucNon ;

for ( [ expression_déclaraNon_1 ] ; [expression_2 ] ; [expression_3 ] )


instrucNon;

=> for (iniNalisaNon; condiNon; instrucNon d’itéraNon)


Interruption & branchement inconditionnel
q break : à l’intérieur d’un bloc de code, elle provoque une sortie de ce bloc de
code.
q continue : permet d’interrompre l’itération courante d’une boucle et de
continuer l’exécution à l’itération suivante après vérification de la condition de
sortie de boucle.
q return : permet une sortie immédiate de la méthode en cours d’exécution
q goto : permet classiquement le branchement en un emplacement quelconque
du programme.

#include <iostream> #include <iostream>


using namespace std ; using namespace std ;
int main () int main ()
{ int n ;
{ for ( int i=1 ; i<=10 ; i++ )
do
{ cout << "debut tour " << i << endl ; { cout << "donnez un nb>0 : " ;
cout << "bonjour\n" ; cin >> n ;
if ( i==3 ) goto sortie ; if (n<0) { cout << "svp >0\n" ;
cout << "fin tour " << i << endl ; continue ;
} }
sortie : cout << "apres la boucle" << endl ; cout << "son carre est : " << n*n << endl ;
} }
while(n) ;
}
Entrainement…
qExercice 1 :
ü Ecrire un programme qui prend un jour de la semaine et
affiche si nous sommes en semaine ou en Weekend.
qExercice 2 :
ü Quels sont les résultats des instructions suivantes:

int i=11; #int i=11;


while (i<10) do
{ {
cout << i << endl; cout << i << endl;
i++; i++;
} } while (i<10)
Entrainement…
qExercice 3 :
ü Ecrire un programme qui lit successivement des nombres
et les affiche par deux. Le programmer doit quitter à la
saisie du caractère ‘q’.
qExercice 4 :
ü Modifier le programme précédent pour qu’il affiche le
plus petit des nombres.
qExercice 5 :
ü Ecrire un programme calculatrice qui demande à
l’utilisateur de fournir trois arguments : deux valeurs
double et un caractère pour représenter l’opération.
Si les arguments d’entrée sont 3.4, 4.2 et ‘+’, le programme doit
afficher : la somme de 3.4 et 4.2 est 7.6.
Les fonctions (1/2)
q Une fonc>on est une suite d’instruc>ons nommée.
q Elle accepte des « arguments » (appelés aussi « paramètres »).
q Elle peut retourner un résultat appelé valeur de retour.

q Une fonc>on :
o Rend le traitement disFnct d’un point de vue logique ;
o Rend le texte du programme plus clair en nommant le
traitement ;
o Permet d’être uFlisée à plusieurs endroits dans un programme
;
o Facilite les tests.
Les fonctions (2/2)
q Exemple :
float fexple (float z, int coef, int n)
{ float val ; // declaration d’une variable "locale" à fexple
val = z * z + coef * z + n ;
return val ;
}

q Arguments formels : lors de la déclaration de la fonction.


q Arguments effectifs : lors de l’appel de la fonction.
q Quand une fonction ne renvoie pas de résultat, on le précise, à la fois
dans l’en-tête et dans sa déclaration, à l’aide du mot-clé void.
q Instruction return définit la valeur du résultat mais elle interrompt aussi
l’exécution de la fonction en revenant dans la fonction qui l’a appelée
(exemple : la fonction main).
q Le prototype de la fonction induit des conversions de type
automatiquement.
Périmetre et Surface du Cercle
#include <iostream>
#include <cmath>
using namespace std;
void perimettreAireCercle(){
cout << "Entrer la valeur du rayon" << endl;
double rayon;
cin >> rayon;
double perimetre = 2 * M_PI * rayon;
double surface = M_PI * pow(rayon, 2);
cout << "Le perimetre du cercle et sa surface de rayon " << rayon << " est:"
<< endl;
cout << "Perimetre du cercle: " << perimetre << std::endl;
cout << "Surface du cercle: " << surface << endl;
}

int main(){
cout << "Saisir un premier nombre" << endl;
int a;
cin >> a;
cout << "Saisir un deuxieme nombre " << endl;
int b;
cin >> b;
int moyenne = (a + b) / 2;
cout << "La moyenne de " << a << " et " << b << " = " << moyenne << endl;
perimettreAireCercle();
return 0;
}
Périmetre et Surface du Cercle
#include <iostream>
#include <math.h>
using namespace std;
Cele foncmon ne retourne rien !!!
Cette fonction fait plusieurs choses
void perimetreAireCercle(){
différentes !!! : surface et périmètre…
cout << "Entrer la valeur du rayon" << endl;
double rayon;
cin >> rayon;
double perimetre = 2 * M_PI * rayon;
double surface = M_PI * pow(rayon, 2);
cout << "Le perimetre du cercle et sa surface de rayon " << rayon << " est:"
<< endl;
cout << "Perimetre du cercle: " << perimetre << std::endl;
cout << "Surface du cercle: " << surface << endl;
}

int main(){
cout << "Saisir un premier nombre" << endl; L’affichage s’effectue dans la fonction.
int a;
cin >> a;
cout << "Saisir un deuxieme nombre " << endl;
int b;
cin >> b;
int moyenne = (a + b) / 2;
cout << "La moyenne de " << a << " et " << b << " = " << moyenne << endl;
perimetreAireCercle();
return 0;
}
Ce code est à réorganiser !!!
Périmetre et Surface du Cercle
#include <iostream>
#include <math.h>
using namespace std;

int main(){
cout << "Saisir un premier nombre" << endl;
int a;
cin >> a;
cout << "Saisir un deuxieme nombre " << endl;
int b;
cin >> b;
int moyenne = (a + b) / 2;
cout << "La moyenne de " << a << " et " << b << " = " << moyenne << endl;
perimetreAireCercle();
return 0;
}

Que se passe –t- il si on inverse le main et la fonction PerimetreAireCercle ?


void perimetreAireCercle(){
cout << "Entrer la valeur du rayon" << endl;
double rayon;
cin >> rayon;
double perimetre = 2 * M_PI * rayon;
double surface = M_PI * pow(rayon, 2);
cout << "Le perimetre du cercle et sa surface de rayon " << rayon << " est:"
<< endl;
cout << "Perimetre du cercle: " << perimetre << std::endl;
}
Comment résoudre ce problème ?
Périmetre et Surface du Cercle
#include <iostream>
#include <math.h>
using namespace std;

void perimetreAireCercle();

int main(){
cout << "Saisir un premier nombre" << endl;
int a;
cin >> a;
cout << "Saisir un deuxieme nombre " << endl;
int b;
cin >> b;
int moyenne = (a + b) / 2;
cout << "La moyenne de " << a << " et " << b << " = " << moyenne << endl;
perimetreAireCercle();
return 0;
}

void perimetreAireCercle(){
cout << "Entrer la valeur du rayon" << endl;
double rayon;
cin >> rayon;
double perimetre = 2 * M_PI * rayon;
double surface = M_PI * pow(rayon, 2);
cout << "Le perimetre du cercle et sa surface de rayon " << rayon << " est:"
<< endl;
cout << "Perimetre du cercle: " << perimetre << std::endl;
}
Périmetre et Surface du Cercle
include <iostream>
#include <math.h>

using namespace std;


float perimetreCercle(float rayon){
return 2 * M_PI *rayon;
}

float surfaceCercle(float rayon){ M_PI définit dans <math.h>


return M_PI*powf(rayon, 2);
}

int main() {
float rayon;
cout<<"Entrer le rayon : "<<endl;
cin>>rayon;
cout<<endl;
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl;
cout<<"Surface de cercle de rayon " <<rayon <<" = " <<surfaceCercle(rayon)<<endl;
cout<<endl;
return 0;
}
Périmetre et Surface du Cercle
include <iostream>
#include <math.h>

using namespace std;


void modifierRayon(float rayon){
rayon++;
}

int main() {
float rayon;
cout<<"Entrer le rayon : "<<endl;
cin>>rayon;
cout<<endl;
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl;
modifierRayon(rayon)
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl
cout<<endl;
return 0;
}

Affichage du périmètre semblable malgré l’appel de la fonction modifierRayon…


Pourquoi ?
Périmetre et Surface du Cercle
include <iostream>
#include <math.h>

using namespace std;

void modifierRayon(float rayon){


rayon++;
}
transmission du rayon par valeur…

int main() {
float rayon;
cout<<"Entrer le rayon : "<<endl;
cin>>rayon;
cout<<endl;
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl;
modifierRayon(rayon)
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl
cout<<endl;
return 0;
}
Périmetre et Surface du Cercle
include <iostream>
#include <math.h>

using namespace std;

void modifierRayon(float& rayon){


rayon++;
}
solution : transmission du rayon référence…
int main() {
float rayon;
cout<<"Entrer le rayon : "<<endl;
cin>>rayon;
cout<<endl;
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl;
modifierRayon(rayon)
cout<<"Perimetre du cercle de rayon : " <<rayon<< " = "<<perimetreCercle(rayon)<<endl
cout<<endl;
return 0;
}
Transmission des arguments par valeur (1/2)
#include <iostream>
using namespace std ;
void echange (int a, int b) ;
int main ()
{ int n=10, p=20 ;
cout << "-- avant appel : " << n << " " << p << endl ;
echange (n, p) ;
cout << "-- apres appel : " << n << " " << p << endl ;
}
void echange (int a, int b)
{ int c ;
cout << "-- debut echange : "<< a << " " << b << endl ;
c=a;
a=b;
b=c;
cout << "-- fin echange : " << a << " " << b << endl ;
}
Transmission des arguments par valeur (2/2)
q Conséquence de la transmission par valeur : La fonction
échange reçoit deux valeurs correspondant à ses deux
arguments muets a et b. Elle effectue un échange de ces deux
valeurs. Mais, lorsque l’on est revenu dans le programme
principal, aucune trace de cet échange ne subsiste sur les
arguments effectifs n et p.
q L’utilisation du mot clé const sur des arguments muets a une
toute autre signification. Il indique que la valeur
correspondante ne peut être modifiée dans le corps de la
fonction.
void f (const int n)
{ .....
n++ ; // rejeté en compilation
}
Transmission des arguments par reference (1/4)
#include <iostream>
using namespace std ;
void echange (int& , int& ) ;
int main ()
{ int n=10, p=20 ;
cout << "-- avant appel : " << n << " " << p << endl ;
echange (n, p) ;
cout << "-- apres appel : " << n << " " << p << endl ;
}
void echange (int& a, int& b)
{ int c ;
cout << "-- debut echange : "<< a << " " << b << endl ;
c=a;
a=b;
b=c;
cout << "-- fin echange : " << a << " " << b << endl ;
}
Transmission des arguments par reference (2/4)
q Transmission des arguments par référence: considérer la référence
d’une variable revient à considérer son adresse, et non plus sa
valeur..
q Dans l’appel d’une fonction recevant un argument par référence,
l’argument effectif correspondant doit obligatoirement être
modifiable (une expression n’a pas d’adresse, une constante n’est
pas modifiable).
q la transmission par référence, telle que nous venons de l’examiner,
possède deux propriétés distinctes :
1. elle évite la recopie d’informations ;
2. elle permet à une fonction de travailler directement sur
l’argument effectif transmis et, donc, d’en modifier la valeur.
Transmission des arguments par reference (3/4)
q Le mécanisme que nous avons exposé pour la transmission des
arguments par référence s’applique à la valeur de retour d’une
fonction.
int & f ()
{ .....
return n ; // on suppose ici n de type int
}

q Quel est l’intérêt et/ou le danger de ce choix ?


Transmission des arguments par reference (4/4)
q Intérêt : un appel de f provoquera la transmission en retour
non plus d’une valeur, mais de la référence (adresse) de n. on
évitera une recopie, ce qui entraîne un gain de temps
d’exécution qui deviendra intéressant avec de gros objets.

q Danger : n ne peut pas être une variable locale à f car, sinon,


elle serait détruite à la sortie de f et l’on récupérerait dans la
fonction appelante, une adresse à quelque chose qui n’existe
plus.
Surdéfinition de fonctions
q il est possible d’avoir le même prototype de fonction mais avec
des arguments différents.
q Exemple :
void sosie (int) ;
void sosie (double) ;
q Dans ce cas, le compilateur fera appel à la bonne fonction
sosie, en fonction de l’argument.
Déclaration automatique
q Déclaration automatique du type des valeurs de retour :
Depuis C++ 11, on peut effectuer une déclaration automatique
du type de la valeur de retour, afin que son type soit déduit
automatiquement du type de l’expression fournie à
l’instruction return.
auto f(int n) { .....
return n * n ; // le type renvoyé par f sera int
}
q Déclaration automatique du type des arguments muets :
void f(auto n) { ..... }

q Combinaison des deux précédents : auto f(auto n) { return n+5 ; }


ü f(3) = 8
ü f(2.6) = 7.6
ü f('a') = f
Fonctions avec types d’arguments variables
q On peut donc utiliser ce type initializer_list pour transmettre à une
fonction un nombre variable d’arguments, soit de même type, soit d’un
type implicitement compatible avec un type donné.

#include <iostream>
using namespace std;
void f (initializer_list<float> val) // val est une liste de float
{ cout << val.size() << " Valeurs : " ;
for (float v : val) cout << v << " " ;
cout << endl ;
}

int main()
{ f({1.5, 2.3}) ; // liste de 2 valeurs de type float
f({}) ; // liste vide (attention f {} serait considéré comme f sans
arguments)
f ({1.25, 5, 9, 3.4, 7 }) ; // liste de 5 valeurs convertibles en float
}
Entrainement…
q Exercice 1
ü Ecrire un programme qui prend deux chaines de caractères et
les compare en disant si elles sont identiques ou pas.
q Exercice 2
ü Ecrire un programme qui prend en argument le nom d’un
fichier et confirme ou pas qu’il est de type C++.
q Exercice 3
ü Ecrire un programme qui prend en argument un numéro de
téléphone et affiche le nom de l’opérateur auquel il appartient
(Libertis, Airtel ou Gabon Telecom Fixe).
q Exercice 4
ü Ecrire un programme qui permet à un utilisateur de deviner un
mot. Il a le droit de demander au programme une lettre à une
position donnée à (trois reprises maximum) pour deviner le
mot.
Entrainement…
q Exercice 1
ü Ecrire un programme qui prend deux chaines de caractères et
les compare en disant si elles sont identiques ou pas.
q Exercice 2
ü Ecrire un programme qui prend en argument le nom d’un
fichier et confirme ou pas qu’il est de type C++ (extension .cpp).
q Exercice 3
ü Ecrire un programme qui prend en argument un numéro de
téléphone et affiche le nom de l’opérateur auquel il appartient
(Libertis, Airtel ou Gabon Telecom Fixe).
q Exercice 4
ü Ecrire un programme qui permet à un utilisateur de deviner un
mot. Il a le droit de demander au programme une lettre à une
position donnée à (trois reprises maximum) pour deviner le
mot. (attention à l’absence de contrôle d’indice, exemple : ch = « Bonjour »; ch[29]
???).
Le type string (1/2)
q Déclaration et initialisation
string ch1 ; // ch1 est une chaîne initialement vide
string ch2 = "bonjour" ; // initialisation copie
ou :
string ch2("bonjour") ; // initialisation directe

Depuis C++ 11 :
string ch2 = {"bonjour"} ; // initialisation copie
string ch2 {"bonjour"} ; // initialisation directe

string ch3 (10, 'x') ; // ch3 contient : xxxxxxxxxx

string ch4 { 'b', 'o', 'n', 'j', 'o', 'u', 'r' } ; // initialisation directe
string ch4 = { 'b', 'o', 'n', 'j', 'o', 'u', 'r' } ; // initialisation copie

q L’utilisation du type string nécessite l’inclusion du fichier en-tête


<string>. Toutefois, ce dernier est automatiquement inclus avec
<iostream>.
Le type string (2/2)
q Les fonctions size() et empty()
string ch ; // ici ch.size() vaut 0 et ch.empty() vaut true
ch = "bonjour" ; // maintenant ch.size() vaut 7 et ch.empty() vaut false

q Concaténation
string ch2 = "monsieur" ;
string ch = "bonjour " + ch2 ; // ch contient bonjour monsieur

q Accès au caractère d’une chaine à un rang donné


ch[1] = 'a’ ; // ch contient maintenant banjour

q Parcours d’une chaine de caractère (string)


for (auto c : ch ) // ou encore : for (char c : ch)
{ // traitement de c
}

q Comparaison de deux chaines de caractères


if (ch1.compare(ch2) == 0 ) {
cout << " The same" << endl ;
}
Les pointeurs naCfs (1/3)
q Les pointeurs natifs représentent ceux qui existent depuis la
création de C++ avant l’introduction des pointeurs dits
« intelligents » destinés à faciliter la gestion dynamique.

q C++ permet donc de manipuler des adresses par l’intermédiaire


de variables nommées pointeurs.
q Notion de pointeurs – Les opérateurs * et &.
1. int n = 20 ;
2. int *ad = &n ;
3. *ad = 30 ;

Que signifie les trois instructions précédentes ?


Les pointeurs natifs (2/3)
Instructions Observations
int n = 20 ; Initialisation d’une variable de type entier nommée n à la valeur 20.
int *ad = &n ; 1.ad est un pointeur sur un int initialisé avec l’adresse de n.
2.* est un opérateur qui désigne le contenu situé à l’adresse qui le suit.
3.Cette déclaration signifie que *ad, c’est-à-dire l’objet dont l’adresse se
trouve dans ad, est de type int.
4. L’opérateur & est un opérateur unaire qui fournit comme résultat
l’adresse de son opérande. Ainsi, cette instruction place dans la variable ad
l’adresse de la variable n.
*ad = 30 ; affectation à *ad la valeur 30. Or *ad représente l’entier dont l’adresse est
contenue dans ad.

ad n
20

30

ad n
Les pointeurs natifs (3/3)

qLe pointeur ne pointant sur rien est appelé le pointeur


null et se nomme nullptr.
qInitialisation d’un pointeur null : int *ad = nullptr ;
Les pointeurs génériques

qIl existe un type particulier, noté void * qui désigne un


pointeur sur une valeur de type quelconque : on parle
souvent de « pointeur générique ». Il s’agit
(exceptionnellement) d’un pointeur sans type.
qExemple :
float *adf ;
void *ad ;
void g (float *) ;
.....
adf = (float *) ad ; // OK
adf = static_cast <float *> (ad) ; // OK : notation conseillée
La gestion dynamique (1/4)

qAvant C++11, la gestion dynamique reposait


uniquement sur les opérateurs new et delete.

qOn peut naturellement initialiser directement ad lors de


sa déclaration :
int *ad = new int ; // ad est initialisé, mais *ad ne l’est pas
*ad = 20 ; // place la valeur 20 dans *ad

qLorsque l’on souhaite libérer un emplacement alloué


préalablement par new, on utilise l’opérateur delete :
delete ad ;
La gesCon dynamique (2/4)

int main()
{ .....
int *adi = new int (10) ; // alloue un emplacement pour un int
..... // initialisé à 10 et place son adresse
dans adi
// utilisation de cet entier référencé par *adi
.....
delete adi ; // libère l'emplacement alloué
// mais adi existe toujours ; il est conseillé de faire :
adi = nullptr ; // ou adi = 0 avant C++11
}
La gestion dynamique (3/4)

void f(int * ad)


{ .....
delete ad ;
.....
}
int main()
{ int * adi = new int (10) ;
.....
f(adi) ; // à éviter
// ..... ici l'objet pointé par adi n'existe plus
}
Ici, nous transmettons (par valeur) à la fonction f l’adresse d’un
emplacement alloué dans la fonction main. La fonction libère
l’emplacement correspondant. Après retour dans la fonction main,
cet emplacement n’existe donc plus.
La gestion dynamique (4/4)

q Avant C++ 11, il était souvent recommandé d’effectuer la gestion


dynamique en plaçant new dans un constructeur et delete dans
un destructeur, réalisant ainsi ce que l’on nomme souvent une
technique RAII (Ressource Acquisition Is Initialization).
Les pointeurs intelligents (1/2)

q Les pointeurs intelligents, notamment unique_ptr et shared_ptr,


ont le mérite d’automatiser la libération mémoire, en en précisant
les conditions.

int main()
{ .....
{ unique_ptr<int> upi (new int (10)) ; // alloue un emplacement pour un
int
..... // initialisé à 10 et place son adresse dans upi
..... // utilisation de *upi, lvalue représentant l’entier référencé par upi
}
// ici, l’entier référencé par upi est détruit, ainsi que upi
}
Les pointeurs intelligents (2/2)

q Comme son nom l’indique, le shared_ptr permet à un même


emplacement d’être référencé par plusieurs pointeurs de même
type. Un mécanisme dit de « comptage de références » permet
de savoir, à un moment donné, combien de pointeurs référencent
le même objet.
q Lorsque le compteur de références devient nul, cela signifie que
l’emplacement n’est plus référencé par aucun pointeur ; il est
alors libéré.
Les classes et les objets

qUne classe est un type défini par l’utilisateur, dans


lequel se trouvent associées :
ü Des données (membres données)
ü Des méthodes (fonctions membres)

qEn POO, l’encapsulation consiste à restreindre l’accès


aux données par le biais des méthodes.

qDéfinition d’une classe point: destinée à manipuler les


points d’un plan.
Les classes et les objets
q La classe point :
// ------------ Declaration de la classe point ------------------
class point
{ // declaration des membres publics
public : // accessibles depuis l’extérieur de la classe
void initialise (int, int) ;
void deplace (int, int) ;
void affiche () ;
// declaration des membres prives
private :// accessibles uniquement aux fonctions membres de la classe.
int x ;
int y ;
};
Définitions des fonctions membres
Le symbole : : correspond à ce que l’on nomme l’opérateur
de « résolution de portée »,

void point::initialise (int abs, int ord)


{ x = abs ;
y = ord ;
}
void point::deplace (int dx, int dy)
{ x = x + dx ; y = y + dy ;
}
void point::affiche ()
{ cout << "Je suis en " << x << " " << y << "\n" ;
}
U1lisa1on de la classe point
// -------- Utilisation de la classe point ----------------------
int main()
{ point a, b ;
a.initialise (5, 2) ; a.affiche () ;
a.deplace (-2, 4) ; a.affiche () ;
b.initialise (1,-1) ; b.affiche () ;

return 0;
}

a et b sont appelés des instances de la classe point.


Le constructeur et le destructeur.
q Dans la classe point la fonction initialise oblige toutefois
à compter sur l’utilisateur de l’objet pour effectuer
l’appel voulu au bon moment pour initialiser les valeurs
de l’objet.
q si le risque ne porte ici que sur des valeurs non définies,
il n’en va plus de même dans le cas où, avant même
d’être utilisé, un objet doit effectuer un certain nombre
d’opérations nécessaires à son bon fonctionnement,
par exemple : allocation dynamique de mémoire,
vérification de l’existence d’un fichier etc.
q Dans ces cas, l’absence de procédure d’initialisation
peut être catastrophique.
Le constructeur et le destructeur.
q C++ offre un mécanisme très performant pour traiter
ces problèmes : le constructeur.
q Le constructeur est une fonction membre (définie
comme les autres fonctions membres) qui sera appelée
automatiquement à chaque création d’un objet.
q Un objet pourra aussi posséder un destructeur, c’est-à-
dire une fonction membre appelée automatiquement
au moment de la destruction de l’objet.
Constructeur
class point
{ public : // declaration des membres publics
point (int, int) ; // constructeur par initialisation
void deplace (int, int) ;
void affiche () ; // declaration des membres privés
private :
int x ;
int y ;
};
//définition du Constructeur
point::point (int abs, int ord)
{ x = abs ; y = ord ;
}

q Si aucun des mots private et public n’apparait dans la définition


d’une classe, tout se passe comme si private avait été placée. Les
membres deviennent donc inaccessibles.
q point a(1,3) ;// fait appel au constructeur de la classe point.
Constructeur
q point a ; // déclaration utilisable avec un constructeur sans argument
appelé également constructeur par défaut point::point () : x(0), y(0) { }
q Définition d’un constructeur par copie : point (const point &)

qInitialisation possible du constructeur dans l’entête :

point::point (int abs, int ord) point::point (int abs, int ord) : x(abs), y(ord) { }
{ x = abs ; y = ord ;
}
Organisation du code d’une classe
q 3 sortes d’instructions regroupées lors des utilisations
des classes précédentes :
ü la déclaration de la classe ;
ü la définition de la classe ;
ü l’utilisation de la classe.
Déclaration
q les seules instructions de déclaration de la classe dans
un fichier en-tête (extension .h) qu’il suffira d’inclure
(par #include) pour compiler l’application.

//Fichiers entête pour la classe point :


// Fichier point.h
class point
{ /* declaration des membres prives */
int x ;
int y ;
public : /* declaration des membres publics */
point (int, int) ; // constructeur
void deplace (int, int) ;
void affiche () ;
};
Définition
// Fichier point.cpp
#include <iostream>
#include "point.h" // pour introduire les declarations de la classe point
using namespace std ;
/* ----- Definition des fonctions membres de la classe point ---- */

point::point (int abs, int ord) : x(abs), y(ord) { }

void point::deplace (int dx, int dy)


{ x = x + dx ; y = y + dy ; }

void point::affiche ()
{ cout << "Je suis en " << x << " " << y << endl ; }
Autoréférence : le mot-clé this

bool point::coincide (point pt)


{ return ((this -> x == pt.x)) && (this -> y == pt.y)) ;
}
Directive include
q La directive #include possède deux syntaxes très
voisines :
ü <.....> pour les fichiers en-tête standard ;
ü "....." pour les fichiers en-tête fournis par
l’utilisateur.

q Protection contre les inclusions multiples :


#ifndef POINT_H
#define POINT_H
// déclaration de la classe point
#endif
Surdéfinition et Arguments par défaut (1/3)
#include <iostream>
using namespace std ;
class point
{ public :
point () ; // constructeur 1 (sans argument)
point (int) ; // constructeur 2 (un argument)
point (int, int) ; // constructeur 3 (deux arguments)
void affiche () ; // fonction affiche 1 (sans arguments)
void affiche (string) ; // fonction affiche 2 (un argument chaine)
};
Surdéfinition et Arguments par défaut (2/3)
#include <iostream>
using namespace std ;
class point
{ public :
point () ; // constructeur 1 (sans argument)
point (int) ; // constructeur 2 (un argument)
point (int, int) ; // constructeur 3 (deux arguments)
void affiche (string = "") ; // fonction affiche avec un argument par defaut
private :
int x, y ;
};

q remplacement de deux fonctions surdéfinies affiche par


une seule fonction ayant un argument par défaut.
Surdéfinition et Arguments par défaut (3/3)

void point::affiche (string message) // fonction affiche


{ cout << message << "Je suis en : " << x << " " << y << endl ;
}

int main()
{ point a ; // appel constructeur 1
a.affiche () ;
point b (5) ; // appel constructeur 2
b.affiche ("Point b - ") ;
point c (3, 12)

}
Surcharge opérateur (1/2)
class point {
public:
point (int x=0,int y=0);
point(const point& p);
void affiche () const ;
point& operator=(const point&);
bool operator==(const point&);
virtual ~point();
friend ostream& operator << (ostream& out, const point& p);
private :
int x;
int y;
};
};
Surcharge opérateur (2/2)
//Définition
point& point::operator=(const point& p){
// TODO Auto-generated destructor stub
if (&p != this){
x = p.x ;
y = p.y;
}
return *this;
}

bool point::operator==(const point& p){


// TODO Auto-generated destructor stub
return ((x == p.x) &&(y ==p.y)) ;
}
Fonction amie
//définition dans point.h
class point {
public:

point (int x=0,int y=0);


point(const point& p);
void affiche () const ;
point& operator=(const point&);
bool operator==(const point&);
virtual ~point();
friend ostream& operator << (ostream& out, const point& p);
private :
int x;
int y;
};
Les fonctions amies ont accès aux données private. La surcharge des
opérateurs de flux (cout et cin) passe par l’utilisation des fonctions
amies.
//définition dans point.cpp
std::ostream& operator<<(std::ostream& os, const point& p) {
os << "(" << p.x << "," << p.y <<") "<< std::endl;
return os;
}
Les structures
qIl existe un autre mot-clé struct qui joue le même rôle
que class, avec cette seule différence que, par défaut,
les membres sont publics.

class X struct X
{ public : { int x ;
int x ; private :
private : double v ;
double v ; };
};
Les énumérations
qenum couleur {vert, jaune, bleu} ;
enum couleur {vert, jaune, bleu} ;
couleur c1, c2;
c1 = vert ;
c2 = jaune ;

enum couleur_rose {rouge, jaune, blanche} ;


//rejeté à la compilation car il n’est pas possible d’utiliser
un même identificateur (jaune) par une autre énumération.

qenum class couleur {vert, jaune, bleu};


enum class couleur {vert, jaune, bleu} ;
couleur c1, c2;
c1 = couleur::rouge ;
c2 = couleur::vert ;

enum couleur_rose {rouge, jaune, blanche} ;


//ok car il y a une différence entre couleur::jaune
et couleur_rose::jaune.
Récapitulatif :
La classe Point par étape
Déclaration de la classe point
q Déclaration de la classe point dans le fichier point.h
q Les directives du Préprocesseur commencent par #
q #ifndef permet de compiler un bout de programme si une
variable de compilation n’est pas définie.
q La directive #define permet de définir une variable qui sera
utilisé par le préprocesseur.

#ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H

class point {

};#endif //GA_ESGISIIRT3
Données
q Déclaration des données de l’objet qui sont privées
(encapsulation).
q Un point sur un plan se caractérise par son abscisse x et son
ordonné y.

ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H

class point {

private:
int x,y;

};#endif //GA_ESGISIIRT3
Constructeur/destructeur
q Déclaration des trois constructeurs (défaut, initialisation et copie)
q Déclaration destructeur en virtuel
q Le constructeur alloue de la mémoire et le destructeur la libère.
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H

class point {
public:
point() ; // constructeur par défaut
point(int abs, int ord) ; constructeur par initialisation
point(const point& p) ; // contructeur par copie
virtual ~point(); //declaration du destructeur

private:
int x,y;

};#endif //GA_ESGISIIRT3
Initialisation du constructeur
q Initialisation du constructeur dans l’entête
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H

class point {
public:
point(): x(0), y(0) {} ;
Point(int abs, int ord): x(abs), y(ord) {} ;
Point(const point& p) ;
virtual ~point(); //declaration du destructeur

private:
int x,y;

};#endif //GA_ESGISIIRT3
Ajout des méthodes affiche et deplace
q Manupilation des données à travers deux méthodes
q Le mot clé const => pas de modification de l’état (données) de
l’objet.
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H-
class point {
public:
point(): x(0), y(0) {} ;
point(int abs, int ord): x(abs), y(ord) {} ;
point(const point& p) ;
void affiche () const;
void deplace(int dx, int dy);
virtual ~point();

private:
int x,y;
};#endif //GA_ESGISIIRT3
Définition de la classe point
q Définition dans le fichier point.cpp
q L’opérateur :: est qualifié « d’opérateur de portée »;
include <iostream>
#include ”point.h"
point::point(const point& p){
x = p.x ;
y = p.y ;
}

void point::affiche () const {


cout << "("<< x <<","<< y <<") ."<< endl;
}

void point::deplace(int dx, int dy) {


x+= dx ;
y+= dy ;
}
virtual point::~point(){}
Utilisation de la classe point
q Utilisation de la classe point dans le programme principal
(main) :
include <iostream>
#include ”point.h"
using namespace std;

int main() {

point p ;
point p2 (5,6) ;
Point p3 (p2) ;

p.affiche() ;
p2.affiche() ;
p3.affiche();
p3.deplace(5,2);
p3.affiche();
p.deplace();
p.affiche();
return 0;
}
Argument par défaut
q Il est possible d’utiliser des arguments par défaut.
q Dans cet exemple, le constructeur par initialisation joue le même
rôle que le constructeur par défaut.
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H

class point {
public:
point(): x(0), y(0) {} ;
point(int abs=0, int ord=0);
point(const point& p) ;
void affiche () const;
void deplace(int dx, int dy);
virtual ~point();
private:
int x,y;

};#endif //GA_ESGISIIRT3
Utilisation de la classe point
q L’utilisation de la classe point reste la même:
include <iostream>
#include ”point.h"
using namespace std;

int main() {
point p ;
point p2 (5,6) ;

return 0;
}
Surcharge des opérateurs (1/2)
q Déclaration :
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H-
class point {
public:
point(): x(0), y(0) {} ;
point(int abs, int ord): x(abs), y(ord) {} ;
Point(const point& p) ;
void affiche () const;
void deplace(int dx, int dy);
bool operator==(const point& p);
point & operator=(const point& p);
virtual ~point();

private:
int x,y;
};#endif //GA_ESGISIIRT3
Surcharge des opérateurs (2/2)
q Définition
#include <iostream>
#include ”point.h"

bool point::operator==(const point& p){


return ((x == p.x) && (y == p.y));
}

point& point::operator=(const point& p) {


if(&p != this){
x = p.x;
y = p.y;
}
return *this;
}
Surcharge des opérateurs de flux (1/2)
q Les fonctions amies : solution intéressante comme compromis entre encapsulation
formelle des données privées et des données publiques.
q Une fonction amie d’une classe peut accéder à tous ses éléments : mot clé friend.
q Les opérateurs de flux (ou flots) sont surchargés via des fonctions amies
ifndef GA_ESGISIIRT3_POINT_H
#define GA_ESGISIIRT3_POINT_H-
class point {
public:
point(): x(0), y(0) {} ;
point(int abs, int ord): x(abs), y(ord) {} ;
Point(const point& p) ;
void affiche () const;
void deplace(int dx, int dy);
bool operator==(const point& p);
point & operator=(const point& p);
friend ostream& operator << (ostream& out, const point& p);
virtual ~point();
private:
int x,y;
};#endif //GA_ESGISIIRT3
Surcharge des opérateurs de flux (2/2)
q Définition
#include <iostream>
#include ”point.h"

ostream& operator << (ostream& out, const point& p){


out << "(" << p.x << "," << p.y <<") "<< endl;
return out;
}
Utilisation de la classe point
q L’utilisation de la classe point reste la même:
include <iostream>
#include "Point.h"
using namespace std;

int main() {

point p ;
point pointA(15,40);
p.afficher();
cout << pointA ;

point pointB = pointA;

if(pointB == pointA){
cout << "Ils sont égaux" << endl;
}else{
cout << "Ils sont différents" << endl;
}
return 0;
}
Entrainement…
q Exercice 1
ü Ecrire une classe Cercle.
q Exercice 2
ü Ecrire une classe Date
q Exercice 3
ü Ecrire une classe Fraction
q Exercice 4
ü Ecrire une classe Pile
q Exercice 5
ü Ecrire une classe PointColore
Classe générique (Template/Patron)
//Définition & Déclaration dans le fichier point.h (le header)
template <typename T> class point
{ public :
point (T abs=0, T ord=0) ;
void affiche () const ;
private :
Tx;Ty;
};
point (T abs=0, T ord=0)
{ x = abs ; y = ord ;
}

//Utilisation
point <int> ai (3, 5) ;
point <double> ad (3.5, 2.3) ;
Héritage (1/2)
class X
{ public :
..... // partie publique
protected : // accessible pour une classe dérivée
..... // partie protégée
private :
..... // partie privée
};
Héritage (2/2)
class pointcol : public point // pointcol derive de point
{ public :
pointcol (int abs=0, int ord=0, short cl=1) ;
void colore (short cl) { couleur = cl ; }
void affiche () const ; //redefinition de la fonction affiche
short couleur;
};
pointcol::pointcol (int abs=0, int ord=0, short cl=1)
: point(abs, ord), couleur(cl)
{ cout << "++ constr. pointcol : " << abs << " " << ord << " " << cl <<
"\n" ; }

void pointcol::affiche () const


{ point::affiche () ; // appel de affiche de la classe point
cout << " et ma couleur est : " << couleur << endl ;
}
Utilisation de Pointcol
int main()
{ pointcol a(10,15,3) ; // objets
pointcol b (2,3) ; // automatiques
pointcol c (12) ; // .....
pointcol * adr ;
adr = new pointcol (12,25) ; // objet dynamique
delete adr ;
}

.
Destructeur virtuel (1/3)
qPar défaut, certains environnements de développement à
la création d’une classe mettent automatiquement le
destructeur en virtuel.
qLe mot clé virtual nous indique que la classe est
polymorphe, c’est-à-dire que le destructeur peut être
redéfinie dans une classe fille.

Pourquoi rendre le destructeur virtuel ?


Destructeur virtuel (2/3)
class ComposantGraphique {

~ComposantGraphique{libererRessousesGraphiques();} //non virtuel
};

class ZoneEdition : ComposantGraphique {


char*texte

~ZoneEdition{…}
};

Void main (){


ComposantGraphique * composantPtr = new ZoneEdition();
//… utilization de composantPtr.
Delete composantPtr
}

quel destructeur sera appelé ?


Destructeur virtuel (3/3)
q On souhaite que le destructeur de l’objet pointé (ZoneEdition) soit
appelé pour libérer la mémoire occupée.
q Cela implique une connaissance dynamique du type d’objet pointé
par composantPtr : cela suppose que les destructeurs aient été
déclarés virtuels. Ce qui n’est pas le cas ici !!!
q C’est le destructeur de la classe de base qui libère les ressources
graphiques qui sera donc appelé, et la mémoire occupée par char*
texte ne sera pas libérée : il y aura donc une fuite de mémoire
(memory leak en anglais).
q Toutes les ressources allouées (mémoire, ressources graphiques,
connexions réseau, fichiers, base de données) par une application
doivent être libérées, il est donc nécessaire de déclarer les
destructeurs virtuels.
La STL et ses concepts
qLa STL (Standard Template Library) propose des
modèles de classes permettant de manipuler
efficacement des conteneurs.
qCes conteneurs ont trois principaux avantages :
1. Ils gèrent leur propre mémoire ;
2. Ils sont performants ;
3. Ils peuvent être parcourus selon un protocole
unique.
q Le STL propose deux types de conteneurs :
1. Séquentiel : on retrouve un élément grâce à son
index (vector, list & deque) ;
2. Associatif : on retrouve un objet en fournissant
une clé (map, multimap, set et multiset).
Les conteneurs séquentiels
qIls existent trois types de conteneurs dans cette
catégorie :
1. Les vecteurs (vector).
2. Les listes (list).
3. Les listes à double extrémités (deque).

.
Le Template Vector
qIl se rapproche le plus des tableaux C++.
qAvantages par rapport aux tableaux classiques :
1. Il détecte quand on dépasse sa capacité et
s’agrandit automatiquement ;
2. Il dispose de fonctions membres permettant son
utilisation plus simple et plus claire.
q Principal inconvénient :
ü les réallocations grèvent les performances et
peuvent ralentir les vecteurs.
ü Ils ne sont pas adaptés s’ils doivent beaucoup
changer de taille.
Les vecteurs (1/4)

q En programmation, on parle de tableau pour représenter un


ensemble d’éléments de même type, désigné par un nom
unique, chaque élément étant repéré par un « indice » précisant
sa position au sein de l’ensemble.

q Avant la norme C++98, on disposait de ce que nous appelerons


les « tableaux natifs » ; il s’agissait de tableaux dont la taille
(nombre d’éléments) était fixe et définie à la compilation. Ils
souffraient de graves lacunes en ce qui concerne leur
transmission en argument d’une fonction.

q Avec la norme C++98 est apparue la bibliothèque standard,


laquelle dispose d’un type vector qui présente l’avantage d’être à
la fois de taille modifiable et facilement transmissible à une
fonction.
Les vecteurs (2/4)

q Déclaration et initialisation :
ü vector<int> v(10) ; // 10 éléments initialisés à 0.
ü vector<double> v (n, 0.5) ; // n éléments de type double initialisés à 0.5
ü vector<string> vx (3, "xxx") ; //3 éléments de type string initialisés à
"xxx »
ü vector<double> v {1, 2.5, 8, 3.2} // initialisation directe

q Exercice : supposons que nous souhaitions déterminer, à partir


de notes d’élèves, fournies en données, combien d’entre elles
sont supérieures à la moyenne de la classe.
Les vecteurs (3/4)
#include <iostream>
#include <vector> // pour le type vector
using namespace std ;
int main()
{ unsigned int nb ; // nombre de notes
cout << "Donnez le nombre de notes : " ; cin >> nb ;
vector <float> notes (nb) ; // pour les nb notes
for (unsigned int i=0 ; i<nb ; i++) // lecture des notes
{ cout << "Donnez la note numero " << i+1 << " : " ; cin >> notes[i] ;
}
float som = 0 ; // calcul de la somme des notes
for (unsigned int i=0 ; i<nb ; i++) som += notes[i] ;
// ou (C++11 ) : for (auto note:notes) som += note ;
float moy = som / nb ;
cout << "Moyenne de la classe : " << moy << endl ;
int nbm = 0 ; // calcul nb notes >= moyenne
for (unsigned int i=0 ; i<nb ; i++ ) if (notes[i] > moy) nbm++ ;
// ou (C++11 - voir § 1.4) : for (auto note:notes) if (note>moy) nbm ++ ;
cout << nbm << " eleves ont plus de cette moyenne" << endl;
}
Les vecteurs (4/4)
q Les vecteurs multidimensionnelles :
ü vector<vector<int>> v(3) qui correspond à un vecteur
de 3 éléments de type vector<int>.
ü vector<vector<int>> v = { {1, 2, 3, 4}, {2, 3, 4, 5}, {6, 7, 8, 9} } ;
Le Template List
qIl permet de résoudre le principal inconvénient du
Template Vector.
qAvantage :
ü Adapté lorsqu’il y a beaucoup de changement de
taille ;
ü Pas implémenté comme un tableau classique mais
comme une liste chainée bidirectionnelle.
ü Chaque élément point sur l’élément qui le précède
et sur celui qui le suit.
qInconvénient :
qLe seul accès possible à un élément de l’objet est
séquentiel.
qPour atteindre un élément donné il faut atteindre
tous ceux qui le précède ou qui le suivent.
Bilan sur les conteneurs séquentiels
qVector : accès rapide aux éléments.
qList : allocation rapide.
qDeque : insertion autorisée en tête ou en queue
de liste et un accès plus rapide aux éléments par
rapport au Template List. L’insertion en milieu de
liste est proportionnelle à la distance entre le
point d’insertion et l’extrémité la plus proche
Les conteneurs associatifs
qIls diffèrent des conteneurs séquentiels car ils ne
sont pas ordonnés séquentiellement.
qPour retrouver un élément, il ne faut pas fournir
un index entier mais plutôt un objet auquel il est
associé.
qCouple Clé/Valeur.
q 4 Templates dans la STL pour manipuler les
conteneurs associatifs :
ü Les dictionnaires : map et multimap ;
ü Les ensembles (clé et valeur sont un même
objet) : set et multiset.
Les conteneurs map et multimap
qmap : Le conteneur map est formé d’éléments
composés de deux parties : une clé et une
valeur. Un conteneur map permet d’accéder
rapidement à la valeur associée à une clé en
utilisant l’opérateur []

qmultimap : dans un conteneur de type


multimap, une même clé peut apparaître
plusieurs fois ou, plus généralement, on peut
trouver plusieurs clés équivalentes. Bien
entendu, les éléments correspondants
apparaissent alors consécutifs.
Les conteneurs set et multiset
qset : c’est un cas particulier du conteneur map,
dans lequel aucune valeur n’est associée à la clé.
Un élément d’un conteneur set est une
constante ; on ne peut pas en modifier la valeur.

qmultiset : le conteneur multiset est un conteneur


set, dans lequel on autorise plusieurs éléments
équivalents à apparaître. Il correspond à la
notion mathématique de multi-ensemble.
Les adaptateurs de conteneurs
q La STL dispose de trois Patrons (Template en anglais)
dits adaptateurs de conteneurs :
1. stack : destiné à la gestion de piles de type LIFO. (Exemple :
stack <int, vector<int> > s1 ; /* pile de int, utilisant un conteneur vector*/)
2. queue : destiné à la gestion de files d’attente, dites aussi
queues, ou encore piles de type FIFO (First In, First Out)
(Exemple : queue <int, deque<int> > q1 ; /* queue de int, utilisant un
conteneur deque */)
3. priority_queue : ressemble à une file d’attente, dans
laquelle on introduit toujours des éléments en fin ; en
revanche, l’emplacement des éléments dans la queue est
modifié à chaque introduction, de manière à respecter une
certaine priorité définie par une relation d’ordre qu’on peut
fournir sous forme d’un prédicat binaire. (Exemple : priority_queue
<int, deque<int>, greater<int> > q2)
Projet :
“ Le Jeu Devinette”
Projet : Le Jeu “Devinette”

qLe Jeu «Devinette» se joue selon deux modes :


v Mode 1 « UN contre UN » :
ü soit contre une personne en réseau ;
ü soit contre la machine .
v Mode 2 « DEUX contre UN » :
ü Deux personnes en réseau avec la machine.
“ Le Jeu Devinette – Mode 1” ( 1/2)

q Le Jeu «Devinette» dans son Mode 1 se joue à deux :


1. soit contre une personne en réseau ;
2. soit contre la machine.
q Les étapes du jeu sont les suivantes :
1. Un tirage au sort détermine quel est le premier à jouer ;
2. Le premier joueur propose un mot à deviner, ce mot est
inconnu du deuxième joueur. Seule la longueur du mot est
connue par le deuxième joueur ;
3. Le deuxième joueur propose ensuite une lettre:
ü Si cette lettre est présente dans le mot, toutes ses
occurrences sont indiquées.
ü Sinon, il continue à proposer des lettres. Le nombre
d’essai autorisé est fonction de la taille du mot et est
indiqué au deuxième joueur dès le début.
“ Le Jeu Devinette – Mode 1” ( 2/2)

q La partie se termine lorsque chacun des deux joueurs a proposé à


l’autre un mot à deviner et qu’il n’y a pas d’égalité en termes de
point.
ü Chaque joueur qui parvient à deviner un mot, ou à donner un
mot impossible à deviner gagne un point.
ü Lorsqu’il y a égalité, la partie continue, dans ce cas, le joueur
qui a donné le mot à deviner devient celui qui doit deviner le
mot de l’autre joueur.
q A la fin de la partie, celui qui a le plus de points gagne.
q Celui qui perd, voit l’image suivante s’afficher :
______
|/ |
| _O_
| I
| /\
/|\_____
“ Le Jeu Devinette – Mode 2” ( 1/2)

q Le Jeu «Devinette» dans son Mode 2 se joue à deux :


1. Les deux joueurs sont devant le même écran et doivent
deviner le mot proposé par la machine.
q Les étapes du jeu sont les suivantes :
1. La machine demande le nombre de mots à deviner ;
2. Un tirage au sort détermine quel est le premier à jouer ;
3. Chaque joueur a 15 secondes pour proposer une lettre.
4. Le premier joueur propose une lettre:
ü Si cette lettre est présente dans le mot, toutes ses
occurrences sont indiquées.
ü Sinon, le deuxième jour prend la main et fait le même
exercice.
5. Le nombre d’essai autorisé est fonction de la taille du mot et
est indiqué aux deux joueurs dès le début.
“ Le Jeu Devinette – Mode 2” ( 2/2)

q La partie se termine lorsque tous les mots ont été soumis aux deux
joueurs ;
q Lorsqu’un mot est trouvé, le joueur qui a deviné le plus de lettres
dans le mot à deviner gagne un point.
Références
q Delannoy, Claude. Programmer en C++ moderne. Eyrolles.
q Bjarne Straustrup. Programmation, principes et pratiques avec C++. Pearson.
q Chrisrtine Eberhardt. Tout sur le C++. Dunod.
q Aurélien Géron et Fatmé Rawbi. Pour mieux développeer avec C++. Dunod.
q O. Marguin — Cours informatique 2003/2004 – C++ : les bases.
(http://math.univ-lyon1.fr/~omarguin/programmation/C++Polycop1.pdf)
Pour avoir les accents en mode console
#include <windows.h>
Dans le main : SetConsoleOutputCP(CP_UTF8);

Vous aimerez peut-être aussi