1. Chapitre 1 : Généralités sur le langage C++
Chapitre 2 : Classes et objets
Chapitre 3 : Les fonctions amies & sur-définition d’opérateurs
2-1 Les structures en C++
2-2 Les classes
2-3 L’utilisation des objets
2-4 Les constructeurs et les destructeurs
2-5 Les membres statiques
3-1 Les fonctions amies
3-2 La sur-définition d’opérateurs
Plan du cours
1
1-1 Historique
1-2 Déclaration des variables et Constantes
1-3 Les Entrées / Sorties simples
1-4 Principales Instructions structurées
1-5 références - Pointeurs
1-6 Les fonctions
1-7 La gestion dynamique de la mémoire
1-8 Les Entrées / Sorties formatées
2. 2
Chapitre 1 : Généralités sur le langage C++
1-1 Historique
1-2 Déclaration des variables et Constantes
1-3 Les Entrées / Sorties simples
1-4 Principales Instructions structurées
1-5 Les fonctions
1-6 références - Pointeurs
1-7 La gestion dynamique de la mémoire
1-8 Les Entrées / Sorties formatées
3. Chapitre 1 : Généralités sur le langage C++
1-1 Historique
Le C++ a été conçu par Bjarne Stroustrup en 1982 aux ATT Bell Laboratories.
L’idée était d’ajouter au C des possibilités sur l’orienté objet et de palier aux
inconvénients du C.
C'est avant tout une nécessité de répondre à des besoins générés par de gros
projets. Ils nécessitent une façon de travailler plus rigoureuse, pour un code
plus structuré, extensible, réutilisable et enfin si possible, portable.
Le C++ est donc basé sur le C, et reprend pratiquement tous les concepts de
ce langage en introduisant quelques ajouts et modifications.
Nous commençons donc par l’introduction et le rappel des principaux
éléments de ce langage.
3/2
4. 1-2 Déclaration des variables et Constantes
Une variable est un objet repéré par son nom, pouvant contenir des données,
qui pourront être modifiées lors de l'exécution du programme
Les variables en langage C++ sont typées, c'est-à-dire que les données
contenues dans celles-ci possèdent un type
Le nombre d'octets en mémoire dépend du type de la variable
En langage C++, les noms de variables doivent répondre à certains critères :
un nom de variable doit commencer par une lettre (majuscule ou
minuscule) ou un « _ » (pas par un chiffre)
un nom de variable peut comporter des lettres, des chiffres et le
caractère « _ » (les espaces ne sont pas autorisés !)
Un nom de variable ne peut pas être un nom réservé
4/2
5. Exemples
Noms de
variables
Correct /
Incorrect
Raison Forme correcte
Age
Age de personne
123Age
Age-de@personne
_nom
For
Correct
Incorrect Comporte des espaces Age_de_personne
Incorrect Commence par un chiffre Age123
Incorrect Symboles interdits @ et - Age_de_personne
Correct
Incorrect Mot réservé
_707 Correct
Remarque :
Les noms de variables sont sensibles à la casse
Ainsi Nom et nom sont deux variables différentes
5
6. La déclaration de variables
Pour pouvoir utiliser une variable, il faut lui donner un nom, et un type de
donnée ( réserver le bon espace mémoire)
Comme en C , une variable se déclare de la façon suivante :
Nom_de_type Nom_de_la_variable ;
Ou :
Nom_de_type Nom_de_la_variable1 , Nom_de_la_vaiable2 ;
Remarques :
Le langage C++ impose que les variables soient impérativement déclarées
Le langage C++ permet de définir une variable à n'importe quel endroit du
code, afin de le rendre plus lisible
Le langage C++ permet de définir une variable en l’initialisant :
Nom_de_type Nom_de_la_variable = valeur ;
Exemple :
int i=3;
6
7. Portée (visibilité) des variables
Selon l'endroit où on déclare une variable, celle-ci pourra être accessible
(visible) de partout dans le code ou bien que dans une partie de celui-ci (à
l'intérieur d'une fonction par exemple), on parle de portée (ou visibilité)
d'une variable.
variable globale : Lorsqu'une variable est déclarée à l'extérieur de toute
fonction ou de tout bloc d'instruction, elle est accessible
de partout dans le code
variable locale : Une variable déclarée à l'intérieur d'un bloc d'instructions
(dans une fonction ou une boucle par exemple) aura une
portée limitée à ce seul bloc d'instruction. elle est inutilisable
ailleurs
Lorsqu’il existe dans un bloc des variables globales et des variables locales,
portant le même nom, l’utilisation du nom de variable fait référence à la
variable locale.
7
8. int i = 3;
void main()
{
int i = 12;
i = i + i;
}
Exemples
Ici la variable i locale au bloc qui valait 12 va recevoir la
valeur 24
Si on cherchait à ajouter à cette variable locale i la
valeur de la variable globale i défini à l’extérieur, il
faut utiliser l’opérateur C++ appelé
opérateur de résolution de portée
Cet opérateur se note ::
int i = 3;
void main()
{
int i = 12;
i = i + ::i;
}
Dans ce cas, à la valeur de la variable locale i on
ajoute la valeur de la variable globale i notée ::i
La valeur de la variable locale i est alors égale à 15.
D'une manière générale il est tout de même préférable de donner des noms
différents aux variables locales et globales... 8/4
9. La définition des constantes
Une constante est une variable dont la valeur est inchangeable lors de
l'exécution d'un programme.
En C , on utilise #define
#define Pi 3.1415927
Toutefois, avec cette méthode les constantes ne sont pas typées, c'est
pourquoi le C++ utilise le mot réservé const, qui permet de définir une
constante typée
const int A = 26;
const float Pi = 3.14159;
Il est donc nécessaire d'initialiser la constante dès sa définition
9/1
10. Les types de données
Les données manipulées en langage C++, sont typées : pour chaque donnée que
l'on utilise il faut préciser le type de donnée
Les données peuvent être
- des nombres : entiers (int) ou réels, c'est-à-dire à virgules (float)
- des pointeurs (en anglais pointers) : permettent de stocker l'adresse
d'une autre donnée, ils « pointent » vers une autre donnée
En C++ il existe plusieurs types d'entiers, dépendant du nombre d'octets sur
lesquels ils sont codés ainsi que de leur format, c'est-à-dire s'ils sont signés
(possédant le signe - ou +) ou non. Par défaut les données sont signées.
De plus, le langage C++ introduit par rapport au langage C un nouveau type
de donnée appelé bool. Ce type de variable accepte deux états :
true (vrai) : correspondant à la valeur 1
false (faux) : correspondant à la valeur 0
10/3
11. Voici un tableau rappelant les principaux types de données en langage C++
Type de donnée Signification Taille (en octets)
char Caractère 1
short int Entier court 2
unsigned short int Entier court non signé 2
int Entier 2/4 (selon processeur 16/32)
unsigned int Entier non signé 2/4 (selon processeur 16/32)
long int Entier long 4
unsigned long int Entier long signé 4
float Réel 4
double Réel double 8
long double Réel double long 16
bool Booléen 1
11
12. Créer un type de donnée
Il est possible en C++ comme en C de définir un nouveau type de données grâce
au mot clé typedef. Celui-ci admet la syntaxe suivante :
typedef Caracteristiques_du_type Nom_du_type
Ainsi l'instruction suivante crée un type de donnée Ch calqué sur le type char :
typedef char Ch
Conversion de type de données
le fait de modifier le type d'une donnée en un autre.
conversion implicite int x;
x = 8.324; x contiendra 8 après l’affectation
conversion explicite : utilise un opérateur dit de cast pour spécifier
la conversion.
int x;
x = (int)8.324;
x contiendra 8 après l’affectation
le langage C++ rajoute une notation fonctionnelle x = int(8.324); 12/5
13. 13/2
1-3 Les Entrées / Sorties simples
Toutes les fonctions d'entrée/sortie sont regroupées dans une bibliothèque
qu'il faudra inclure en début de tous les programmes utilisant des entrées
sorties. Cette inclusion au programme se fera de la façon suivante :
#include <iostream.h>
L'opérateur de sortie et le flux de sortie
Pour envoyer des valeurs vers un périphérique de sortie (écran, imprimante,...),
le C++ utilise deux composantes :
Le flux de sortie standard cout qui est l'objet contenant les valeurs à exporter
L'opérateur d'insertion ou opérateur de sortie << insère des objets dans le flux
de sortie indiqué à sa gauche.
Ainsi cout <<66; affiche 66 à l'écran.
Syntaxe :
cout << expression << expression <<expression ;
14. 14/3
Exemple :
cout << " Filiere :" <<" n AUTOMATISME"<<endl;
affichera sur deux lignes :
Filiere :
AUTOMATISME
- La chaîne n indique comme en C qu'il s'agit d'un retour à la ligne.
- Le mot clé endl indique à la fois un ordre de saut de ligne et de purge du
contenu du tampon de sortie.
L'opérateur d’entrée et le flux d’entrée
L'opérateur d'entrée >> permet d'indiquer au flux d'entrée cin les variables dans
lesquelles il doit rentrer les valeurs saisies.
Syntaxe :
cin >> expression >> expression >>expression;
15. 15
Exemple :
main()
{
int age;
cout << "Donnez votre âge : ";
cin >>age;
cout << "nDans 10 ans vous aurez " <<age+10 <<"ans" <<endl;
}
Remarque : dans le cas de saisies multiples (cin >>x >>y >>z;), les caractères
séparateurs sont, comme en C, l'espace et le saut de ligne.
16. 16/3
1-4 Principales Instructions structurées
On rappelle, ici, toutes les instructions structurées du langage C++, qui sont
définies déjà dans le langage C
La notion de bloc
Une expression suivie d'un point-virgule est appelée instruction.
Par exemple a++; est une instruction.
Lorsque l'on veut regrouper plusieurs instructions, on peut créer ce que l'on
appelle un bloc, c'est-à-dire un ensemble d'instructions (suivies
respectivement par des points-virgules) et comprises entre les accolades { et }.
Les principales instructions structurées if, while et for peuvent par exemple être suivies
d'un bloc d'instructions à exécuter...
17. 17/6
Syntaxe des principales instructions
if (condition réalisée) {
liste d'instructions
}
if (condition réalisée) {
liste d'instructions
}
else {
autre série d'instructions
}
(condition) ? Instruction_si_vrai : instruction_si_faux ;
Remarques :
La condition doit être entre des parenthèses
S'il n'y a qu'une instruction, les accolades ne sont pas nécessaires
Il est possible de définir plusieurs conditions à remplir avec les opérateurs
&& et ||
18. 18/1
switch (Variable)
{
case Valeur1 :
Liste d'instructions
break;
case Valeur2 :
Liste d'instructions
break;
case Valeur3 :
Liste d'instructions
break;
default:
Liste d'instructions
break;
}
Remarque :
N'oubliez pas d'insérer des instructions break entre chaque test,
19. 19/3
for (compteur; condition; modification_du_compteur )
{
liste d'instructions
}
Par exemple :
for (i=1; i<6; i++)
{
cout<<i<<endl ;
}
il faudra toujours vérifier que la boucle a bien une condition de
sortie. ((i.e. le compteur s'incrémente correctement)
Remarque :
while (condition_réalisée)
{
liste d'instructions
}
20. 20
continue : faire sauter à la boucle une ou plusieurs valeurs sans
pour autant mettre fin à celle-ci.
Exemple :
x=1;
while (x<=10)
{
if (x == 7) {
cout<<"Division par zero"<<endl ;
x++;
continue;
}
a = 1/(x-7);
Cout<<a<<endl ;
x++;
}
21. 21
break : permet d'arrêter une boucle
Exemple :
for (x=1; x<=10; x++)
{
a = x-7;
if (a == 0)
{
cout<<("Division par 0")<<endl;
break;
}
cout<<1/a<<endl ;
}
TD simples
22. 22/2
1-5 Les fonctions
Rappels sur les fonctions:
On appelle fonction un sous-programme qui permet d'effectuer un
ensemble d'instructions par simple appel de la fonction dans le corps du
programme principal.
Avant d'être utilisée, une fonction doit être définie. La définition d'une
fonction s'appelle " déclaration ". La déclaration d'une fonction se fait selon la
syntaxe suivante :
type_de_donnee Nom_De_La_Fonction(type1 argument1, type2 argument2)
{
liste d'instructions
}
Où : type_de_donnee : le type de valeur retournée (void,char, int, float...)
argument i : nom d’argument
type i : type de l’argument i
23. 23/2
Pour exécuter une fonction, il suffit de faire appel à elle en écrivant
son nom suivi d'une parenthèse ouverte, des arguments puis d'une
parenthèse fermée :
Nom_De_La_Fonction (argument1, argument2);
Exemple :
Déclaration : double somcarre (float a, float b)
{
return a*a + b*b;
}
Appel :
double v;
float n1, n2;
…//saisie de n1 et n2
v = (somcarre(n1, n2) – (n1+n2)) / n;
Remarque : Une fonction peut ne pas avoir d’arguments lors de sa
déclaration , elle est alors appelée sans argument en plaçant les parenthèses
après son nom.
24. 24/1
Prototype d’une fonction
Le prototype d'une fonction est une description de la fonction qui est
placée en début de programme avant la fonction principale main().
Un prototype de fonction ressemble à ceci :
Type_de_donnee Nom_De_La_Fonction( type1, type2) ;
Exemples:
void Affiche_car(char, int);
int Somme(int, int);
25. 25
La surcharge des fonctions
La surcharge est la possibilité de donner le même nom à plusieurs fonctions.
La différence entre les fonctions se fait par rapport au type et au nombre des
paramètres.
Le compilateur accepte alors ces fonctions de même nom et les distingue lors de
leur appel grâce au type et au nombre des paramètres fournis.
Deux fonctions de même nom sont surchargées lorsqu'elles :
Ont au moins un paramètre de type différent ou
Diffèrent par le nombre des paramètres ou
Ont des types de retour différents
26. 26/5
Les prototypes de fonctions suivants peuvent cohabiter dans un même
programme :
void Echanger(int *, int *, int i=10); // Ambiguïté lors de l’appel, avec la première
// fonction lorsqu'on utilise le paramètre par
// défaut. Cette déclaration sera refusée par
// l e compilateur
int Echanger(int *, int *) // Type de retour différent
void Echanger(float *, float *); // Type des paramètres différent
void Echanger(int *, int *);
int somme( int p1, int p2)
{
return (p1 + p2);
}
float somme( float p1, float p2)
{
return (p1 + p2);
}
float somme( float p1, float p2, float p3)
{
return (p1 + p2 + p3);
}
int somme( float p1, int p2)
{
return (int(p1) + p2);
}
Autres exemples :
27. 27
1-6 références & Pointeurs
Quand on déclare une variable avec un nom et un type, un emplacement
mémoire du type de la variable est créé à une certaine adresse avec son nom
pour y accéder.
L’emplacement mémoire recevra la valeur de la variable lors d’une affectation.
int x ; // une déclaration
x = 3 ; /* une affectation */
Le C ++ ,comme le C, permet de manipuler dans le programme, les adresses des
emplacements mémoire des variables.
&x désigne l’adresse de la variable x.
On peut déclarer des pointeurs d’un type qui sont des variables contenant des
adresses de variables de ce type avec le symbole *.
int * p ; // p : un pointeur sur un entier
p = &x ; // p vaut l’adresse de x
28. 28
L’opérateur * s’appelle l’opérateur de déréférencement
*p désigne la valeur contenue dans l’emplacement mémoire dont l’adresse
est p.
int y = *p ; // y vaut 3
int x ; // une déclaration
x = 3 ; // une affectation
int * p ; // p : un pointeur sur un entier
p = &x ; // p vaut l’adresse de x
int y = *p ; // y vaut 3
Récapitulons :
29. 29/2
En C++, on peut aussi déclarer une référence à une variable existante.
Une référence se déclare avec l’opérateur &.
Une référence est un synonyme (un nom supplémentaire) pour désigner
l’emplacement mémoire d’une variable.
int & z = x ; // z est une référence a x, z vaut 3
Si on change la valeur de x, la valeur de z est aussi changée et inversement.
De même avec *p.
x = 4; // x et z valent 4, *p aussi
z = 5; // x et z valent 5, *p aussi
*p = 6; // *p, x et z valent 6
Remarques :
Noter que les opérateurs & et * sont inverses l’un de l’autre. On a
toujours :
*(&x) = x et &(*p) = p
30. 30/2
• Attention, on ne peut pas déréférencer un pointeur qui ne contient
pas une adresse valide.
Il faut initialiser le pointeur avant :
int * q ;
*q = 7 ; // plantage
int * q ;
q = &x;
*q = 7 ; // ok
La notion de référence est directement liée au passage de paramètres à des
fonctions en C++ .
Référence et appel de fonction :
Nous savons que lorsque nous voulons transmettre à une fonction la valeur
d'une variable ou au contraire la donnée réelle (en fait l'adresse), nous
n'utilisons pas les mêmes méthodes.
31. 31
Par exemple, soit les fonctions suivantes :
int FaitQqch( int a, int b)
{
int nRet;
if( a==0 )
a=10;
nRet = a + b;
return nRet;
}
int FaitQqch2( int * a, int * b)
{
int nRet;
if( *a==0 )
*a=10;
nRet = *a + *b;
return nRet;
}
Nous voyons tout de suite que dans le cas d'un appel comme celui-ci :
...
int a, b, c, d;
a = 0;
b = 5;
c = FaitQqch(a,b);
d = FaitQqch2(&a,&b);
...
c et d auront la même valeur, par contre, ce
qui est intéressant, c'est qu'à la sortie de
FaitQqch, la valeur restera inchangée, alors
que pour FaitQqch2, a vaudra désormais 10 !
Ceci est dû au passage par adresse, et non
par valeur.
32. 32/1
En revanche, voyons ce que notre traitement devient en utilisant les références.
int FaitQqch3(int &a , int &b)
{
int nRet;
if( a==0 )
a=10;
nRet = a + b;
return nRet;
}
Le "&" signifie que l'on passe par référence.
La ligne de déclaration de la fonction est en fait la seule différence avec une
transmission par valeur, d'un point de vue code. C'est-à-dire que l'utilisation des
variables dans la fonction s'opère sans "*" et l'appel à la fonction sans "&".
33. 33/3
1-7 La gestion dynamique de la mémoire
Nous avons rappelé que la durée de vie d'une variable s'étendait durant toute la
portée de son nom. La mémoire est allouée, utilisée et puis elle est rendue au
système à la fin de portée.
L’utilisation de la mémoire peut se faire grâce à:
d'une part l'utilisation de pointeurs
d'autre part à des opérateurs permettant de gérer explicitement
l'allocation mémoire et sa libération.
L'allocation-libération de mémoire étant à la charge du programmeur, elle peut
se faire dans n'importe quel ordre. La structure de pile n'est alors plus adaptée, et
de fait la mémoire est allouée dans une autre zone de la mémoire, appelée le tas
(heap).
Le programmeur doit effectivement gérer la libération de mémoire... s'il ne le fait
pas, ou s'il le fait mal, les pires conséquences (à savoir un plantage du programme)
peuvent arriver.
34. 34/3
Les opérateurs de gestion de la mémoire :
En C, la gestion dynamique de la mémoire fait appel aux fonctions malloc et
free. En C++, on utilise les fonctions new et delete.
En C :
/* pour un simple pointeur */
int * pInt;
pInt = (int*)malloc(1*sizeof(int));
free(pInt);
...
/* pour un tableau */
pInt = (int*)malloc(100*sizeof(int));
free(pInt);
...
En C++ :
// pour un simple pointeur
int * pInt;
pInt = new int;
delete pInt;
...
// pour un tableau
pInt = new int[100];
delete pInt;
...
En C++, bien que l’utilisation de malloc et free soit toujours permise, il est
très conseillé de n’utiliser que new et delete.
35. 35/3
1-8 Les Entrées / Sorties formatées
La librairie standard définit tout un jeu de manipulateurs extrêmement utiles
pour définir les options de formatage et pour effectuer des opérations de base
sur les flux.
Exemple : Le symbole endl, utilisé pour effectuer un retour à la ligne dans les
opérations d’écriture sur les flux de sortie est un manipulateur. Son rôle consiste
simplement à écrire le caractère de retour à la ligne et à appeler la méthode
flush() du flux de sortie (méthode qui déclenche le transfert du contenu du flux).
les manipulateurs les plus simples qui ne prennent pas de paramètre sont
résumés sur le tableau suivant :
Manipulateur Description
endl Envoie un caractère de retour à la ligne sur le flux et
synchronise le tampon par un appel à la méthode flush()
ends Envoie un caractère nul terminal de fin de ligne sur le flux
flush Synchronise le tampon utilisé par le flux par un appel à la méthode
flush()
boolalpha Affiche les booléens sous forme textuelle
noboolalpha Désactive l’affichage en mode texte des booléens
36. 36
Manipulateur Description
hex Formate les nombres en base 16
oct Formate les nombres en base 8
dec Formate les nombres en base 10
fixed Utilise la notation en virgule fixe pour les nombres à virgule
scientific Utilise la notation en virgule flottante pour les nombres à virgule
Left Aligne les résultats à gauche
Right Aligne les résultats à droite
internal Complète la représentation de la variable avec des espaces
complémentaires à une position fixe déterminée par la locale
courante. Si cette dernière ne spécifie aucune position de
remplissage particulière, le remplissage s’effectue à droite par
défaut
showbasexe Indique la base de calcul utilisée
noshowbase N’indique pas la base de calcul utilisée
showpoint Utilise le séparateur de virgule dans les nombres à virgule,même
si la partie fractionnaire est nulle
37. 37
Manipulateur Description
noshowpoint N’utilise le séparateur de virgule que si la partie fractionnaire
des nombres flottants est significative
showpos Écrit systématiquement le signe des nombres, même s’ils sont
positifs
noshowpos N’écrit le signe des nombres que s’ils sont négatifs
uppercase Écrit les exposants et les chiffres hexadécimaux en majuscules
nouppercase Écrit les exposants et les chiffres hexadécimaux en minuscules
unitbuf Effectue une opération de synchronisation du cache géré par le
tampon du flux après
chaque écriture
nounitbuf N’effectue les opérations de synchronisation du cache géré par
le tampon du flux que lorsque cela est explicitement demandé
38. 38
utilisation des manipulateurs sur un flux de sortie
int main()
{
cout << "On affiche le booléen true sous forme textuelle: tt";
cout << boolalpha << true << endl;
cout << "On repasse en mode binaire pour ";
cout << "afficher le booléen false: t";
cout << noboolalpha << false << endl;
cout << "Hex permet aussi d’afficher les booléens ";
cout << "en mode binaire: t";
cout << hex << false << endl;
cout << "On écrit le nombre 63 en hexadécimal: tttt";
cout << hex << 63 << endl;
cout << "En majuscules: ttttttt";
cout << uppercase << 63 << endl;
cout << "On repasse en base 10 pour afficher 63: ttt";
cout << dec << 63 << endl;
cout << "Avec le signe: ttttttt";
cout << showpos << 63 << endl;
39. 39
cout << "On affiche un flottant sur 15 caractères minimum, n";
cout << "en remplissant les vides avec des *: ttt";
cout << setfill(‘*’) << setw(15) << 3.151592 << endl;
cout << "On recommence avec un alignement à gauche,n";
cout << "sans le signe: tttttt";
cout << left << noshowpos << setw(15) << 3.151592 << endl;
}