C vers C++
version support : 2.0
Introduction
• C++ a été développé dans les années 1980 parBjarne Stroustrup
• http://www2.research.att.com/~bs/homepage.html
• C++ est un langage normalisé par l'ISO
ISO/CEI 14882:1998– ISO/CEI 14882:1998
– ISO/CEI 14882:2003
– ISO/CEI 14882:2011 (C++11)
– ISO/CEI 14882:2014 (mise à jour de la norme)
• C++ est un autre langage que C
antislashn.orgC vers C++ 2
Introduction
• Principales fonctionnalités ajoutées par rapport au langage C– déclaration reconnue comme une instruction (repris en C99)– opérateurs new et delete– type de donnée bool– mot clé const (repris en C99)– espaces de nom– classes et tout ce qui est lié à la POO– classes et tout ce qui est lié à la POO– surcharge des opérateurs– gestion des exceptions– identification des types à l'exécution
• RTTI : run-time type identification
– commentaire // (repris en C99)– fonction inline (repris en C99)– paramètres par défaut dans les fonctions– les références
antislashn.orgC vers C++ 3
Hello, world
• L'exemple incontournable
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
inclusion du fichierd'entête, le ".h" n'est pasnécessaire (sauf pour C)
utilisation d'espace denommage pour éviter lescollisions de nom
type de retourobligatoire
hello.cpp
antislashn.orgC vers C++ 4
{cout << "Hello, world" << endl;system("PAUSE");return EXIT_SUCCESS;
}
objet de typeostreamreprésentant leflux de sortie opérateur
d'insertion
return facultatifsi absent un return 0 esteffectué
Programmation orientée objet
• L'objet– propriétés (variables de l'objet)– méthodes (fonctions manipulant les variables de l'objet)
• Concepts de base– encapsulation
• il n'est pas possible d'accéder aux données de l'objet• il n'est pas possible d'accéder aux données de l'objet– uniquement par l'intermédiaire des méthodes
– classe• généralisation de la notion de type• structure de données + fonctions
– héritage• permet de créer une nouvelle classe sur une classe existante
– polymorphisme• possibilité de traiter de la même manière des objets de type différents
antislashn.orgC vers C++ 5
Conventions de nommage
• Utilisez des noms de fonction, de variable quipermettent une auto-documentation du code
• Attention aux conventions de pré-fixage des nomsde variables par leur type
• int intNb;
– que devient le préfixe si le type vient à évoluer ?
• int est remplacé par long, pour rester cohérent il faut queintNb devienne longNb
antislashn.orgC vers C++ 6
Type C++
• Les types du langage C sont repris par C++– entiers (nb octets donné à titre indicatif)
• char : 1 octet• short int (ou short) : 2 octets• int : 4 octets• long int (ou long) : 4 octetslong int (ou long) : 4 octets• long long : 8 octets• peuvent être signed, ou unsigned
– types flottants• float : 8 bits exposants, 23 bits mantisse (4 octets)• double : 11 bits exposants, 52 bits mantisse (8 octets)• long double : 15 bits exposants, 64 bits mantisse (12 octets)
– type booléen• bool : valeurs true ou false
antislashn.orgC vers C++ 7
C++11 – pointeur NULL
• Le mot clé nullprt a été ajouté commeconstante du langage
– constante de type nullptr_t
• non convertible vers un entier
• convertible vers void*• convertible vers void*
– assignable à tout type de pointeur• en C++ il est interdit d'assigner un void* à un pointeur
d'un type différent
antislashn.orgC vers C++ 8
Quelques différences avec C
• La bibliothèque standard C++ définit de nouvellesclasses et templates.
– nous utiliserons régulièrement
• la classe string
– représente une chaîne de caractères– représente une chaîne de caractères
• la classe vector
– peut-être vu comme un tableau dynamique
– le type des éléments doit être précisé lors de la déclaration
• ces classes seront vues plus en détail plus tard
antislashn.orgC vers C++ 9
Quelques différences avec C
• Exemple d'utilisation de string et vector
#include <iostream>#include <vector>#include <string>
using namespace std;
int main(){
vector-string.cpp
inclusionsnécessaires
construction
antislashn.orgC vers C++ 10
int main(){string nom = "toto";vector<int> v;
for(int i=0 ; i < 5 ; i++)v.push_back(i);
cout << nom << endl;for(int i=0 ; i < v.size() ; i++)
cout << v[i] << " ";cout << endl;
}
ajout dynamiqued'éléments
d'un vecteur deint
Affichage à l'écran
• Opérateur d'insertion <<
– surcharge de l'opérateur de décalage à gauche
• un même symbole peut désigner plusieurs opérateursdistincts
– l'opérande de droite est envoyé vers le flux– l'opérande de droite est envoyé vers le flux
– opérateur associatif de droite vers la gauche
• permet d'enchainer les affichages
– de nombreuses options et opérateurs permettent deformater la sortie
antislashn.orgC vers C++ 11
Lecture au clavier
• Opérateur d'extraction >>– surcharge de l'opérateur de décalage vers la droite
• cin représente l'entrée standard– instance de la classe istream
cout << "Entrez un nombre : ";cin >> nb;
– instance de la classe istream
– l'opérateur >> est associatif de gauche à droite
• un séparateur quelconque (espace, tabulation,…) est utilisépour l'analyse
– n'est pas recueilli
– de nombreuses options et opérateurs sont disponibles
antislashn.orgC vers C++ 12
cin >> nb >> nom;
C++11 – Inférence de type
• Nouvelle sémantique pour le mot clé auto
– indiquait la classe de stockage
• comportement par défaut
• auto était rarement utilisé
– depuis C++11 auto prend la place du type dans la– depuis C++11 auto prend la place du type dans ladéclaration de variable
• le type sera alors celui de la rvalue
• la variable de type auto doit donc être initialisée lors de ladéclaration
antislashn.orgC vers C++ 13
C++11 – Inférence de type
• Le mot clé decltype permet de typer unevariable à partir du type d'une expression
int number = 1;auto y = number;decltype(y) z;
y et z seront de type int
• auto peut être utilisé pour le type de retourd'une fonction
– le type est précisé après la parenthèse fermante
antislashn.orgC vers C++ 14
int aa;auto foo() -> decltype(aa){
return aa++;} le type de retour sera int
C++11 – boucle "foreach"
• L'instruction for permet de parcourir unintervalle
– tableau, conteneurs de la STL définissant les fonctionsmembres begin() et end()
antislashn.orgC vers C++ 15
int tab[5] = {1, 2, 3, 4, 5};for (int &x: tab) {
x *= 2;}
C++11 – type array
• Type std::array<TYPE,TAILLE>
– inclure <array>
• Possède des méthodes
– size(), front(), back(), at(), empty(), …
– les crochets [] sont toujours utilisables
antislashn.orgC vers C++ 16
const int TAILLE = 5;
array<int,TAILLE> tab = {1,2,3,4,5};
for(int nb : tab){cout << nb << endl;
}
C++11 – énumérations fortement typées
• Utilisation de enum class ou enum structà la place de enum
– pas de conversion implicite vers le type int
• conversion explicite seulement
– accès aux éléments par l'opérateur de portée ::– accès aux éléments par l'opérateur de portée ::
antislashn.orgC vers C++ 17
enum class State{STOP,START};State s = State::STOP;
Fonctions inline
• Une fonction inline donne la possibilité à C++d'insérer le code sans créer de fonction
– pas de création de fonction, pas de copie sur la pile
– exemple :inline int carre(int x) {return x*x;}inline int carre(int x) {return x*x;}
– évite les effets de bords des définitions de macro du C#define carre(x) ((x)*(x))
– n'est qu'une requête au compilateur, celui-ci peut l'ignoreret créer une vraie fonction
– ne peut pas faire l'objet d'une compilation séparée
– ne peut pas être manipulée par un pointeur vers fonction
antislashn.orgC vers C++ 18
Fonctions inline
• En fonction des réglages du compilateur, lesfonctions peuvent être inline automatiquementou pasinline int max(int a, int b){return a>b?a:b;}
int main(void)
antislashn.orgC vers C++ 19
int main(void){
int i,j,k;cin >> j >> k;i = max(j,k);cout << i << endl;
}
_TEXT SEGMENT?max@@YAHHH@Z PROC; max, COMDAT
; _a$ = ecx; _b$ = eax
; 5 : int max(int a, int b){return a>b?a:b;}
00000 3b c8 cmp ecx, eax00002 7e 02 jle SHORT $LN4@max00004 8b c1 mov eax, ecx
$LN4@max:00006 c3 ret 0
?max@@YAHHH@Z ENDP; max
Fonctions inline
• Sous Visual Studio
– sur le projet faire clic droit puis propriétés
antislashn.orgC vers C++ 20
Les références
• Nouveauté notable de C++ par rapport à C
– ne doit pas être confondue avec la notion de pointeur
– le passage par adresse (contenu d'un pointeur) n'estpas le passage par référence
– une référence est un alias d'un objet en mémoire– une référence est un alias d'un objet en mémoire
– syntaxe :type & identificateur = expression;
antislashn.orgC vers C++ 21
int main(){int i = 30;int &ri = i;
ri += 10;cout << i << " == " << ri << endl;cout << "@i = " << &i << endl;cout << "@ri = " << &ri << endl;
} reference.cpp
Les références
• Une référence doit être initialisée lors de sadéclaration
– avec un objet (expression devant être une lvalue)
• int &i = 10; n'est pas valide– dépend du compilateur et version de C++– dépend du compilateur et version de C++
• const int &i = 10; est valide
– on ne peut pas déclarer un tableau de références• int i, j;
int &tab[] = {i,j}; est illégal
– en pratique les références sont utilisées dans le cadrede passage de paramètres et retour de fonction
antislashn.orgC vers C++ 22
Passage d'arguments par référence
• En C les arguments sont passés par valeur– il y a création sur la pile d'une nouvelle variable
– copie de l'argument passé• dans le cas d'un pointeur il y a bien copie du contenu du pointeur,
c'est-à-dire de l'adresse de l'objet pointé
– la valeur initiale de la variable passée n'est pas– la valeur initiale de la variable passée n'est pasaffectée par les modification dans la fonction
• Le passage par référence crée un nouveau nompour la variable passée à la fonction– les modifications dans la fonction impacterons la
valeur de la variable initiale
antislashn.orgC vers C++ 23
Passage d'arguments par référence
• La fonction classique d'échange permet d'illustrerle passage par référence
void echanger(int &i, int &j){
int t = i;i=j;j=t;
}
reference-echanger.cpp
– les valeurs de a et b ont bien été échangées
antislashn.orgC vers C++ 24
}int main(){
int a = 10;int b = 30;cout << "Avant a == " << a << " et b == " << b << endl;echanger(a,b);cout << "Apres a == " << a << " et b == " << b << endl;
}
Retour de référence
• En C une fonction de la forme
– retourne la valeur de x
int f(){
...return x;
}
– retourne la valeur de x
• il y a création sur la pile d'une variable à laquelle estaffectée la valeur de x
• l'expression f() est une rvalue, non pas une lvalue
– on ne peut pas écrire
f() = expression;
antislashn.orgC vers C++ 25
Retour de référence
• En C++ une fonction peut retourner une référence
– dans ce cas l'expression f() est une référence vers la
int &f(){
...return x;
}
– dans ce cas l'expression f() est une référence vers lavariable x
• c'est-à-dire une lvalue– on peut écrire
f() = expression;
• de nombreuses fonctions ou templates C++ retournent desréférences
– operator<<, operator>>, etc…
antislashn.orgC vers C++ 26
Retour de référence
• Exemple
int & augmenter(int &x){
x += 10 ;return x;
}int main(){
int i = 5;
retour-reference.cpp
– l'expression augmenter(i) est une référence pourla variable i du main
• i vaudra 30
antislashn.orgC vers C++ 27
int i = 5;augmenter(i) += 15;cout << i << endl;system("PAUSE");
}
Retour de référence
• Ne pas retourner une référence à une variablelocale d'une fonction– la variable locale est créée sur la pile et sa durée de
vie est celle de la fonction• comme il ne faut pas retourner l'adresse d'une variable
locale lorsque l'on travaille par pointeur• comme il ne faut pas retourner l'adresse d'une variable
locale lorsque l'on travaille par pointeur
• Attention aux conversions de type– si i avait été de type char l'appel de la fonction aurait
généré une conversion de type, donc une variabletemporaire aurait été créée sur la pile qui n'est pas lavariable i
antislashn.orgC vers C++ 28
Surcharge des fonctions
• C++ permet de surcharger les fonctions
– un même nom de fonction peut-être associé àplusieurs fonctions
– le compilateur génère plusieurs fonctions de nomsdifférents en tenant compte du type des paramètresdifférents en tenant compte du type des paramètres
• la signature de la fonction
• le type de retour n'est pas utilisé
• le modificateur const est utilisé
– le choix de la fonction à appeler est déterminé par letype des arguments
antislashn.orgC vers C++ 29
Surcharge des fonctions
• Le compilateur va générer 4 fonctions– afficher_Fi, afficher_Fc, afficher_Fd,afficher_FPc
• F pour fonction, P pour pointeur, R pour référence, C pourconstant
génèrerait– f(const char &) génèrerait f_FRCc
antislashn.orgC vers C++ 30
void afficher(int i){ cout << "int : " << i << endl; }
void afficher(char c){ cout << "char : " << c << endl; }
void afficher(double d){ cout << "double : " << d << endl; }
void afficher(char * s){ cout << "string : " << s << endl; }
surcharge-fonctions.cpp
Surcharge des fonctions
• Appel de fonctions C par un programme C++
– soit une fonction C int f(int); est définie dansune librairie C
– la simple déclaration de son prototype est insuffisante
• le compilateur lui donnera un nom différent, tenant compte• le compilateur lui donnera un nom différent, tenant comptedes paramètres
• l'éditeur de lien ne pourra pas la retrouver
– la déclaration doit être faite par• extern "C" int f(int);
• si plusieurs fonctions :– extern "C" {déclarations et inclusions}
antislashn.orgC vers C++ 31
Surcharge des fonctions
• Pour choisir la fonction surchargée le compilateur utilise uncertain nombre de règles1. il recherche une version avec correspondance exacte de type
entre les arguments et les paramètres2. il essaie d'appliquer les règles habituelles de promotion
numérique3. il essaie d'appliquer les règles de conversion standard sur les3. il essaie d'appliquer les règles de conversion standard sur les
pointeurs et références (classes et classes dérivées)4. il essaie d'appliquer les règles de conversion définies par le
développeur (vues plus loin)5. il vérifie s'il existe une version à un nombre variable
d'arguments
• Au cours de ces étapes, si une ambigüité est détectée lecompilateur lève une erreur
antislashn.orgC vers C++ 32
C++11 – fonctions lambda
• fonction anonyme
– fonction qui n'a pas de nom
– peut-être passée comme argument
• par exemple à la fonction std::for_each, à la place d'unfoncteurfoncteur
– syntaxe :[](paramètres) -> return_type { corps; }
• [] : captures
• si return_type n'est pas précis il est déduit par lecompilateur
antislashn.orgC vers C++ 33
C++11 – fonctions lambda
• Exemple
vector<int> nombres = {0,1,2,3,4,5,6,7,8,9};
for_each(nombres.begin(), nombres.end(), [](int element) {cout << element << endl;
liste d'initialisation C++11
antislashn.orgC vers C++ 34
});
lambda
[](int a, int b) -> int{ return a+b; };
type de retour
C++11 – fonction lambda
• Il est possible d'affecter une lambda à unevariable
– de type std::function
• adaptateur générique de fonction permettant d'appeler unecible appelablecible appelable
– cible pour laquelle operator() est défini
– on fournit alors le type de retour et la liste des arguments
» void s'il n'y a pas de type de retour
• ou de type auto
antislashn.orgC vers C++ 35
std::function<int (int,int)> add1 = [](int a, int b){ return a+b; };auto add2 = [](int a, int b){ return a+b; };
type de retour suivi du type desparamètres
C++11 – fonctions lambda
• Closure
– une fermeture est une fonction qui capture desvariables à l'extérieur de celle-ci
– il faut préciser les variables à capturer entre []
– la capture est effectuée– la capture est effectuée
• par référence– les éventuelles modifications affecterons la variable capturée
• par valeur– c'est une copie de la variable capturée, les modifications
n'affecterons pas la variable capturée
antislashn.orgC vers C++ 36
C++11 – fonctions lambda
• Exemples
int somme = 0;auto add = [&somme](int a, int b){ somme=a+b; };
antislashn.orgC vers C++ 37
int somme = 0;auto add = [somme](int a, int b){ somme=a+b; };
C++11 – fonctions lambda
• Résumé de la syntaxe de capture– [] : pas de variable externe
– [i,&j] : i capturée par valeur, j par référence
– [&] : toutes les variables externes sont capturées parréférenceréférence
– [=] : toutes les variables externes sont capturées parvaleur
– [&,x] : x est capturée par valeur, les autresvariables externes sont capturées par référence
– [=,&x] : x est capturée par référence, les autresvariables externes sont capturées par valeur
antislashn.orgC vers C++ 38
Arguments par défaut
• Il est possible d'affecter une valeur par défaut àtout ou partie des paramètres d'une fonction
void afficher(int i, int b=0, int c=3){…}
– l'affectation par défaut peut remplacer certainessurcharges explicites d'une fonction
antislashn.orgC vers C++ 39
Opérateur de portée ::
• L'opérateur de portée :: permet d'utiliser unevariable globale masquée par une variable locale
int x = 10;int main(){
int x = 20;cout << "x local == " << x <<endl;
antislashn.orgC vers C++ 40
cout << "x local == " << x <<endl;cout << " x global == " << ::x << endl;
}surcharge-fonctions.cpp
Ordres des déclarations
• Contrairement au C, les déclarations peuvent êtreeffectuées lors de la première utilisation d'unevariable
int main(){
int x = 10;
x est visible dans toute lafonction main
i est déclaré seulement pour
antislashn.orgC vers C++ 41
int x = 10;for(int i = 0 ; i<10 ; i++){cout << i << endl;}if(int i=x-11 > 0)
cout << "i > 0" << endl;else
cout << "i <= 0" << endl;cout << i << endl;
}
i est déclaré seulement pourle bloc for
i est déclaré seulement pourle bloc if - else
erreur de compilation carpas de déclaration pour ce i
declarations.cpp
Allocation dynamique de mémoire
• En C l'allocation de mémoire est effectuée par unmalloc, la libération de mémoire par free
• En C++ l'allocation de mémoire est effectuée parnew, la libération par delete
antislashn.orgC vers C++ 42
int main(){
int *pi;int *ti;pi = new int;ti = new int[50];
delete pi;delete [] ti;
}
affectation de l'adressed'un int
affectation de l'adressed'un tableau de 50 int
libération pour un int
libération pour un tableaude int
new-simple.cpp
Allocation dynamique de mémoire
• L'opérateur new permet d'initialiser un objet detype défini :
int * pi = new int(10);
• Lorsque new retourne l'adresse d'une instance declasse ou de structure, cette initialisation n'estclasse ou de structure, cette initialisation n'estpossible que si un constructeur adéquat a étéprévu.
• Il n'est pas possible d'initialiser un tableau allouépar new
antislashn.orgC vers C++ 43
Allocation dynamique de mémoire
• Allocation à une adresse imposée
• Gestionnaire de manque de mémoire– il faut vérifier que new (comme malloc) ne retourne pas la
valeur null
int *pi;int *ti;pi = new ((int *)0X0FFF) int;ti = new (pi+10) int[50];
new-simple.cpp
valeur null
– un gestionnaire peut être mis en place pour tout retour denull par new
• le rôle de ce gestionnaire est de tenter de libérer de la mémoire– à la fin de l'exécution du gestionnaire, la main est donnée de nouveau au new
» sauf si dans le gestionnaire il y a une instruction type exit(…)
• le gestionnaire (handler) ne doit attendre aucun paramètre et neretourne rien
• l'adresse du handler est passée à la fonction set_new_handler
antislashn.orgC vers C++ 44
Allocation dynamique de mémoire
• Exemple de handler
void gestionnaire(){
cout << "Plus de memoire" << endl;system("PAUSE");exit(1);
}mise en place du gestionnaire
antislashn.orgC vers C++ 45
int main(){
set_new_handler(gestionnaire);int *pi;int *ti;pi = new int;ti = new int[1000000000];
delete pi;delete [] ti;
}
demande trop importante
mise en place du gestionnaire
new-handler.cpp
Emploi de const
• const int i = 10;
– définit une valeur qui restera constante
• i est de type const int
– en C++ le compilateur peut ne pas définir un objet enmémoiremémoire
– doit être initialisé à la définition
• par une expression constante, connue à la compilation
– un objet const est de classe static
antislashn.orgC vers C++ 46
Emploi de const
• int i;const int *p = &i;– p est un pointeur qui pointe sur un objet constant
• l'initialisation de p n'est pas obligatoire
– i peut être modifié directement, pas par *p• int i;int *const p = &i;int *const p = &i;– p est un pointeur constant qui pointe sur un objet i
• l'initialisation est obligatoire• p ne peut pas varier• i peut être modifié directement ou via *p
• const int * const p = &i;– p est un pointeur constant qui pointe sur un objet constant
• initialisation obligatoire• p ne peut pas varier, *p n'est pas une lvalue
antislashn.orgC vers C++ 47
Emploi de const
• Paramètre de type const
– si on fournit un argument de type const à une fonction, lecompilateur génère une erreur
• certains compilateurs génèrent un warning
– il faut définir le paramètre de la fonction comme const– il faut définir le paramètre de la fonction comme const
• Nous reviendrons sur le modificateur const lors del'étude des classes
antislashn.orgC vers C++ 48
void f(const int &i) { cout << i << endl; }
const int j = 20;int main(){
f(j);system("PAUSE");
}
Forçage de type
• En C++ il est illégal de convertir un pointeurvoid* en un autre type sans forçage explicite dutypeint *p = malloc(20);
• n'est pas légal en C++• n'est pas légal en C++
int *p = (int *) malloc(20);
• est légal en C++
antislashn.orgC vers C++ 49
Forçage de type
• Comme en C
– un pointeur vers un objet non constant ou vers unefonction peut être affecté à un pointeur void*
– l'adresse d'un objet constant ne peut pas être affectéà un pointeur non constant sans forçage de typeà un pointeur non constant sans forçage de type
antislashn.orgC vers C++ 50
const int j = 10;int * q1 = &j; // ILLEGALvoid *q2 = &j; // ILLEGALvoid *q3 = (int *)&j; // LEGAL mais dangereuxconst void *q4 = &j; // CORRECT
const.cpp
Forçage de type
• C++ introduit de nouveaux opérateurs de forçagede type :
– static_cast
– dynamic_cast
–– const_cast
– reinterpret_cast
– syntaxe :• opérateur <type> (expression);
antislashn.orgC vers C++ 51
Forçage de type
• static_cast– permet d'effectuer toute conversion standard, si les types sont
cohérents entre eux• type vers type• pointeur vers pointeur• référence vers référence
– ne permet pas de retirer le modificateur const– ne permet pas de retirer le modificateur const
• dynamic_cast– effectue des vérifications à l'exécution– utilisé pour le polymorphisme
• sera vu plus loin
antislashn.orgC vers C++ 52
const int i = 10;char c = static_cast <char> (3.14); // CORRECTint *p = static_cast <int *> (&i); // ILLEGALint *q = static_cast <int *> (20000); // ILLEGAL
forcage-type.cpp
on force l'adressepointée par q
Forçage de type
• const_cast
– permet la conversion d'une entité const en entiténon const
const int i = 10;double j = 10;int *p = const_cast <int *> (&i); // CORRECT
forcage-type.cpp
• reinterpret_cast
– permet de forcer le typage entre types différents
– ne permet pas de retirer le modificateur const
antislashn.orgC vers C++ 53
int *p = const_cast <int *> (&i); // CORRECTint q = const_cast <int> (j); // ILLEGAL
const int i = 10;int *p = reinterpret_cast <int *> (&i); // ILLEGALint *q = reinterpret_cast <int *> (2000); // CORRECT
forcage-type.cpp
Structure
• C++ conserve la notion de structure du C– en C++ la structure réunie des données et des
fonctions membres• la syntaxe d'accès reste la même :
– point . pour un accès direct
– flèche -> pour un accès par pointeur– flèche -> pour un accès par pointeur
– trois niveaux de visibilité sont prévus• public : visibilité en tout point du programme
– visibilité par défaut sur les structures
• private : visibilité par les fonctions membres et amies
• protected : visibilités par les fonctions membres et lesstructures dérivées
antislashn.orgC vers C++ 54
Structure
• Exemplestruct identite{
char * nom;void afficher(){
cout << "Nom : " << nom << endl;}
}; pas besoin de préfixer par
antislashn.orgC vers C++ 55
};
int main(){
identite id;id.nom = "Toto";id.afficher();system("PAUSE");
}
pas besoin de préfixer parstruct
structure-identite-1.cpp
Structure
• Déclaration des fonctions membres
– une fonction membre définie à l'intérieur de lastructure est par défaut inline
– une fonction membre peut-être définie à l'extérieurde la structurede la structure
antislashn.orgC vers C++ 56
struct identite{
char * nom;void afficher();
};
void identite::afficher(){
cout << "Nom : " << nom << endl;}
déclaration dans lastructure
définition par le nomcomplètement qualifié de lafonction en utilisantl'opérateur de portée
structure-identite-2.cpp
Structure
• La notion d'encapsulation demande à ce que– les données membres soient privées
• il faut donc des fonctions membres publiques pour les lire et lesmodifier
– les accesseurs / mutateur, ou getter / setter
– les fonctions membres publiques présentent l'interface– les fonctions membres publiques présentent l'interfaced'utilisation de la structure
– l'initialisation de la structure est effectuée à l'aide defonctions adaptées : les constructeurs
• En C++ la structure est peu utilisée car les classessont généralement plus adaptées– par défaut les membres sont privés
antislashn.orgC vers C++ 57
Classe
• Une classe est déclarée par le mot clé class
• La notion de classe ne diffère que sur un seulpoint de celle de structure : les membres sontprivés par défaut– encapsulation des données– encapsulation des données
• Ordre de déclaration des classes– les classes doivent être déclarées avant d'être
employée
– une déclaration incomplète peut-être utilisée• syntaxe : class X;
– forward declaration (déclaration anticipée)
antislashn.orgC vers C++ 58
Classe
• Exempleclass Point{
int x,y;public :
void afficher();void init(int,int);
};x et y sont privées :mise en place d'une fonctiond'initialisation
Point-1.cpp
antislashn.orgC vers C++ 59
void Point::afficher(){
cout << "Point en (" << x << "," << y << ")" << endl;}
void Point::init(int x, int y){
Point::x = x;this->y = y;
}utilisation du pointeur thisthis est l'adresse del'objet qui invoque lafonction
utilisation de l'opérateurde portée
d'initialisation
Classe - .h et .cpp
• Le fichier .h contient
– les propriétés de la classe
– les prototypes des méthodes
• si une méthode est définie dans le .h, elle est considéréecomme inlinecomme inline
• Le fichier .cpp contient les définitions desméthodes
antislashn.orgC vers C++ 60
Classe - .h et .cpp
• Il est fréquent qu'une classe A contienne unattribut de type classe B et que cette mêmeclasse B contienne un attribut de type A– attribut ou argument de fonction
• On se retrouve très vite avec un problème• On se retrouve très vite avec un problèmed'inclusion cyclique
• L'utilisation d'une forward declaration dans le .hpermet de résoudre ce problème– tant que l'on utilise un pointeur ou une référence le
compilateur à juste besoin de connaitre l'existence dela classe
antislashn.orgC vers C++ 61
Classe - .h et .cpp
class B;
class A{B *ptrB;void foo();
};
A.h#include "A.h"#include "B.h"void A::foo(){
A& a = ptrB->getA();}
A.cpp
class A;B.h
#include "A.h"#include "B.h"
B.cpp
Pointeur vers Bpas besoin du .h
antislashn.orgC vers C++ 62
class B{A &refA;
public:B(A &a);A& getA();
};
#include "B.h"
B::B(A &a):refA(a){};
A& B::getA(){return refA;}
#include "A.h"class C{
A a;};
C.h#include "C.h"
C.cpp
Référence vers Apas besoin du .h
Propriété de type Ale compilateur à besoindu constructeur A()inclusion du .h
Classe – conventions de nommage
• Une spécification de développement est un choixconsensuel– établi des règles communes de développement
– améliore la compréhension du code par l'équipe
• Une convention de nommage doit-être mise en• Une convention de nommage doit-être mise enplace– fait partie des spécifications de développement
– doit permettre une auto-documentation du code
– doit avoir un choix approuvé des noms de variables,fonctions, classe, …
antislashn.orgC vers C++ 63
Classe – conventions de nommage
• Les noms donnés à vos classes, méthodes, …forment votre vocabulaire de développement
• Une normalisation est importante
– exemple :
• le nom d'une classe commence par une majuscule
• le nom d'une méthode, variable, propriété par uneminuscule
• utilisation de l'intercapitalisation– camelcase
antislashn.orgC vers C++ 64
Classe – règles de conception
• Encapsulation des propriétés
– par défaut elle sont privées
– mise en place de méthodes d'accès
• exemple de convention : setXxx(…) getXxxx()
• Donner des noms explicites aux méthodes• Donner des noms explicites aux méthodes
• Généraliser le vocabulaire
– utiliser le polymorphisme
• nommer une méthode d'affichage afficher() quelque soitla classe
antislashn.orgC vers C++ 65
Classe – règles de conception
• Exemple issu de Qt – style
– garder à l'esprit que si le code est au moins écrit unefois, il sera lu de nombreuses fois
• il devra être compréhensible et auto-documenté
• ainsi le constructeur suivant est peut intuitif à écrire et à lire• ainsi le constructeur suivant est peut intuitif à écrire et à lire
• il peut être avantageusement remplacé par
antislashn.orgC vers C++ 66
QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical, 0, "volume");
QSlider *slider = new QSlider(Qt::Vertical);slider->setRange(12, 18);slider->setPageStep(3);slider->setValue(13);slider->setObjectName("volume");
Classe – membres de classe
• Les variables de la classe sont appelées– propriétés (attributs en UML)
• Les fonctions de la classe sont appelées– méthodes (opérations en UML)
• Les constructeurs sont des méthodes spécifiques qui sontappelées lors de la construction de la classeappelées lors de la construction de la classe– on parle aussi d'instanciation– sera vu en détail plus tard
• Les destructeurs sont des méthodes spécifiques qui sontappelées avant la désallocation de l'objet– sera vu en détail plus tard
• L'ensemble des méthodes et propriétés forme lesmembres de la classe
antislashn.orgC vers C++ 67
Classe – membres de classe
• Le modificateur const peut être utilisé pour
class Point{int x,y;
public:Point(int i, int j){x=i; y=j;}int getX(){ return x;}int getY(){ return y;}void setX(int x){this->x = x;}void setY(int y){this->y = y;}
};
propriétés privées
constructeur
accesseurs pour lespropriétés privées
• Le modificateur const peut être utilisé pourindiqué qu'une méthode ne modifiera pas lespropriétés de la classe
antislashn.orgC vers C++ 68
class Point {int x,y;
public:Point(int i, int j){x=i; y=j;}int getX()const { return x;}int getY()const { return y;}void setX(int x){this->x = x;}void setY(int y){this->y = y;}
};
les getteurs sont constle compilateur vérifiera lecontrat
Classe – membres de classe
• Une méthode constante ne pourra invoquer quedes méthodes constantesclass Point {
int x,y;public:
Point(int i, int j){x=i; y=j;}int getX() { return x;}
erreur de compilation cargetX() n'est pas const
antislashn.orgC vers C++ 69
int getX() { return x;}int getY() { return y;}void setX(int x){this->x = x;}void setY(int y){this->y = y;}void afficher() const {cout << "x == " << getX() << endl;}
};
getX() n'est pas const
Classe – membres de classe
• Une propriété peut être déclarée mutable pourpouvoir être modifiée par une méthode const
– ATTENTION : le contrat annoncé par la méthode n'estplus respecté
déclaration de x mutable
antislashn.orgC vers C++ 70
class Point {int mutable x;int y;
public:Point(int i, int j){x=i; y=j;}int getX() { return x;}int getY() { return y;}void setX(int x){this->x = x;}void setY(int y){this->y = y;}void verifier() const {if(x==0) x=10;}
};
déclaration de x mutable
méthode const
pas d'erreur de compilationsur l'affectation
Classe – membres de classe
• Les propriétés représentent l'état d'une instance
– en mémoire il y à deux objets de type Point possédant
int main(){Point p1(1,2);Point p2(10,20);
}
– en mémoire il y à deux objets de type Point possédantchacun leur état
antislashn.orgC vers C++ 71
p1:Point
x 1
y 2
p2:Point
x 10
y 20
Classe – membres de classe statique
• Certaines propriétés peuvent être partagées partoutes les instances d'une classe
– propriétés statiques
class Point {static int compteur; propriété partagée par
antislashn.orgC vers C++ 72
static int compteur;int x;int y;
public:Point(int i, int j){x=i; y=j; compteur++;}static int getNbPoints() { return compteur;}
};
int Point::compteur = 0;
int main(){Point p1(1,2);Point p2(10,20);cout << Point::getNbPoints() << endl;
}
propriété partagée partoutes les instances
initialisation de lapropriété statique
méthode statique utilisablesans instancier la classe
invocation de la méthodestatique
Classe – membres de classe statique
• Une méthode statique ne peut utiliser que desmembres statiques
– elle "existe" en dehors de toute instance
p1:Point
antislashn.orgC vers C++ 73
p1:Point
x 1
y 2
p2:Point
x 10
y 20
compteur 2
Classe – membre de classe statique
• Exemple de membre de classe statique de typetableauclass A{private:
static int tabInt[];public:
static int* getTabInt() {return tabInt;}static int getNbElements();
tableau_statique.h
antislashn.orgC vers C++ 74
static int getNbElements();};
int A::tabInt[] = {1,2,3,10,20,30};
int A::getNbElements(){return sizeof(tabInt)/sizeof(tabInt[0]);}
int main(){A a;for(int i=0 ; i<a.getNbElements() ; i++)
cout << a.getTabInt()[i] << endl;}
Classe – pointeur this
• Le pointeur this représente l'instance en cours
• Lors de l'appel des méthodes d'une classe, cepointeur est passé comme premier paramètre
– pointeur "caché"
• la méthode
est converti en
• Le pointeur this n'est pas passé aux méthodesstatiques
antislashn.orgC vers C++ 75
void setY(int y){this->y = y;}
void setY(Point *const this, int y){this->y = y;}
Fonctions et classes amies
• Une fonction qui n'est pas membre d'une classe n'apas accès aux membres privées de cette classe.
• Cette contrainte peut être levée en rendant publiqueles membres privées de la classe auprès de certainesfonctions– mot-clé friend– mot-clé friend
– déclaration des fonctions amies dans la classe– des classes peuvent-être déclarées comme classes amies
• Ceci ne devrait-être qu'une pratique exceptionnelle– des designs patterns permettent de conserver
l'encapsulation• visiteur, commande, …
antislashn.orgC vers C++ 76
Fonctions et classes amies
• Exemple
class Point{
private :int x,y;
public :void init(int,int);
friend void afficher(Point);friend class Ligne;
déclaration de la fonctionamie
déclaration d'une classeamie
Point-2.cpp
antislashn.orgC vers C++ 77
friend class Ligne;};
void afficher(Point p){
cout << "Point en (" << p.x << "," << p.y << ")" << endl;}
class Ligne{public :
void afficher(Point p1, Point p2){
cout << "Ligne depuis (" << p1.x << "," << p1.y << ") et (" << p2.x << "," << p2.y << ")" << endl;}
};
utilisation des membresprivés
Fonctions amies
• Certaines surcharges d'opérateurs peuvent êtreeffectuées via des fonctions amies
– simplification du codage et accès à tous les membres
– la surcharge de l'opérateur d'insertion << permet dedéfinir comment une instance est insérée dans un fluxdéfinir comment une instance est insérée dans un flux
antislashn.orgC vers C++ 78
class Point{int x,y;
public:void init(int,int);friend ostream& operator<<(ostream &o,const Point &p);
};
ostream& operator<<(ostream &o,const Point &p){o << "Point en (" << p.x << "," << p.y << ")" << endl;return o;
}…
Point-3.cpp
Constructeurs et destructeur
• Un constructeur est une fonction membre d'uneclasse– le nom de la fonction est le même que la classe– le constructeur n'a pas de type de retour (pas mêmevoid)
– il peut y avoir plusieurs constructeurs– il peut y avoir plusieurs constructeurs• constructeur par défaut• constructeur de copie• constructeurs de conversion
• Le destructeur est une fonction membre d'une classedont le nom est celui de la classe préfixe par tilde (~)– appelé automatiquement lorsque l'objet est détruit– n'attend pas de paramètre, n'a pas de type de retour
antislashn.orgC vers C++ 79
Constructeurs et destructeurs
• Les objets sont construits dans l'ordred'apparition des déclarations– attention : dans certaines configuration l'ordre d'appel
des constructeurs des variables globales ou statiquesn'est que partiellement défini en C++n'est que partiellement défini en C++
• il peut varier d'un build à l'autre– cf. C++ faq-lite [10.11] [10.12]
– cf. Google Style Guide "Static and Global Variables"
• L'ordre d'appel des destructeurs est inverse del'ordre d'appel des constructeurs
• C++ garantit l'appel du destructeur
antislashn.orgC vers C++ 80
Constructeur par défaut
• Il ne possède pas d'arguments– prototype : nom_classe()
• Il est appelé automatiquement– lors de la définition d'un objet
• <classe> identificateur;<classe> identificateur;
– lors d'une allocation dynamique par new• <classe> * pointeur;
• Si aucun constructeur n'est défini, le compilateur enfournit un par défaut– ATTENTION : dès qu'un constructeur est défini, ce
constructeur par défaut n'est plus fournit• il faut alors le fournir explicitement
antislashn.orgC vers C++ 81
Constructeur par défaut
• Exemple (extrait) class Point{
private :int x,y;
public :void afficher();Point();
};
Point::Point(){
x=10;
prototype du constructeurpar défaut
définition du constructeur
Point-4.cpp
antislashn.orgC vers C++ 82
x=10;y=20;
}…int main(){
Point p;Point * pt = new Point();p.afficher();pt->afficher();
delete pt;}
définition du constructeurpar défaut
objet de type Point allouésur la pile
objet de type Point allouésur le tas (les parenthèsessont facultatives)
libération de la mémoire
Constructeur par défaut
• ATTENTIONTrouvez l'erreur !!!
class Point{
private :int x,y;
public :void afficher();Point();
};
Point::Point(){
x=10;
antislashn.orgC vers C++ 83
x=10;y=20;
}…int main(){
Point p;Point p1();Point * pt = new Point();p.afficher();pt->afficher();delete pt;
}
Constructeur par défaut
• ATTENTIONPoint p1();
– déclare le prototype de lafonction p1
– ne génère pas d'erreur à la
class Point{
private :int x,y;
public :void afficher();Point();
};
Point::Point(){
x=10;– ne génère pas d'erreur à lacompilation
– génère un warning à l'éditionde liens si p1 n'est pas utilisé
• génère une erreur si p1 estutilisé
antislashn.orgC vers C++ 84
x=10;y=20;
}…int main(){
Point p;Point p1();Point * pt = new Point();p.afficher();pt->afficher();delete pt;
}
Destructeur
• Le destructeur est appelé lorsqu'un objet sort desa portée– prototype : ~nom_classe();
• pas de type de retour, pas même void
• pas de paramètres• pas de paramètres
– en général nécessaire s'il y eu allocation de mémoirepar la classe
• notion de composition
– le destructeur peut-êtreinvoqué par l'instance elle-même
• z.~z();
antislashn.orgC vers C++ 85
class Z{int *tab;
public:Z(int taille) {tab = new int[taille];}~Z() { delete [] tab;}
};
Constructeurs de conversion
• Une classe peut comporter plusieursconstructeurs de conversion
– prototype :• nom_classe(liste_de_type);
– il utilise la liste des arguments passés pour construire– il utilise la liste des arguments passés pour construireun nouvel objet
antislashn.orgC vers C++ 86
Constructeurs de conversion
• Exemple (extrait) :class Point{
private :int x,y;
public :void afficher();Point();Point(const Point &);Point(int);Point(int,int);
};Point::Point(int x)
Deux prototypes deconstructeurs de conversion
Définition du premierconstructeur de conversion
Point-6.cpp
antislashn.orgC vers C++ 87
Point::Point(int x){
this->x = x;y = x;
}Point::Point(int x, int y){
this->x = x;this->y = y;
}int main(){
Point p(50,47);Point * pt = new Point(6);
…}
Définition du secondconstructeur de conversion
Création d'une instance surla pile
Création d'une instance surle tas
Constructeurs de conversion
• NotePoint p(3,4);
etPoint p = Point(3,4);
peuvent conduire à un code généré différent, dans lepeuvent conduire à un code généré différent, dans lesecond cas le compilateur peut créer un objettemporaire puis le recopier dans la variable p
• Note
– Point p = 16; appellera le constructeur deconversion Point(int) .
antislashn.orgC vers C++ 88
Constructeurs de conversion
• Note
– Point p = (Point)6.3; provoquera untranstypage et l'appel du constructeur Point(int)
– Point p = (Point)6,4; provoquera un appel dePoint(int) puis l'évaluation de l'expression 4Point(int) puis l'évaluation de l'expression 4
– C++ n'admet qu'un seul niveau de conversion parconstructeur. Soient deux classes A et B ayant commeconstructeurs
• A(int); et B(A);
• une définition telle que B b = 5; est illégale
antislashn.orgC vers C++ 89
Constructeurs de conversion
• Un constructeur à un seul argument définit uneconversion de type qui est appelée implicitementpar le compilateur
Point p = (Point)6.3;
Point p = (Point) 'a';
– des effets de bords peuvent engendrer des ambigüités– des effets de bords peuvent engendrer des ambigüitésqui rendent le programme incompilable
– les conversion implicites peuvent être inhibées enutilisant explicit
• Soyez cohérent et lisible dans l'appel desconstructeurs
antislashn.orgC vers C++ 90
Constructeurs de conversion
• Exemple de conversion ambiguë (extrait)class Z{
public:Z(){};
};
class X{public:
X(Z z){};};
antislashn.orgC vers C++ 91
};
class Y{public:
Y(Z z){};};
void f(X x){ cout << "X" << endl; }void f(Y y){ cout << "Y" << endl; }
int main(){
Z z;f(z);
}
Deux conversions possibles,vers Y ou Xle programme ne compile pas
constructeurs-sans-explicit.cpp
Constructeurs de conversion
• Exemple avec explicit (extrait)class Z{
public:Z(){};
};
class X{public:
X(Z z){};}; la conversion vers la classe
antislashn.orgC vers C++ 92
};
class Y{public:
explicit Y(Z z){};};
void f(X x){ cout << "X" << endl; }void f(Y y){ cout << "Y" << endl; }
int main(){
Z z;f(z);
}
la conversion vers la classeY est inhibée
la conversion est effectuéevers la classe X
constructeurs-avec-explicit.cpp
Constructeur de copie
• Il est appelé implicitement– lors d'une initialisation de la forme :
• T idBis = id; où T est le nom de la classe et id une instance de laclasse T
– peut aussi s'écrire : T idBis(id);
– lors du passage par copie d'un objet en argument d'unefonctionfonction
– lorsqu'une fonction retourne un objet par valeur– lorsqu'un pointeur sur un objet reçoit une valeur par
l'opérateur new• T *pt = new T(t); où t est une instance de T
• S'il n'existe pas de constructeur de copie, C++ en fournit unpermettant une copie superficielle de l'objet– copie bit à bit de l'objet, attention donc aux membres de type
pointeur
antislashn.orgC vers C++ 93
Constructeur de copie
• Deux prototypes possibles• nom_classe (nom_classe &);
• nom_classe (const nom_classe &);
– préférable car passage d'un argument const ou non
• ATTENTION– il faut distinguer une création par copie– il faut distinguer une création par copie
• T new_t = t;
– d'une affectation• old_t = t; où old_t et t sont des objets déjà existants
– il est alors fait appel à l'opérateur d'affectation (=)• par défaut, effectue une copie de surface, il faut donc
souvent le redéfinir si certains membres sont des pointeurs
antislashn.orgC vers C++ 94
Constructeur de copie
• Exemple (extrait) :class Point{
private :int x,y;
public :void afficher();Point();Point(const Point &);
prototype constructeur decopie
Point-5.cpp
antislashn.orgC vers C++ 95
Point(const Point &);
};…Point::Point(const Point &p){
x = p.x;y = p.y;
}…int main(){
Point p;Point p1 = p;…
}
définition du constructeurde copie
Création d'une instance dePoint par appel duconstructeur de copie surl'instance p
Tableau d'objets
• La syntaxe du C est utilisable pour initialiser destableaux d'instances de classe
– la classe doit posséder les constructeurs adéquats
class Point{Point-7.cpp
antislashn.orgC vers C++ 96
class Point{int x, y;public:
Point(){x=y=0;}Point(int a) {x=y=a;}Point(int x, int y){this->x = x; this->y = y;}void afficher(){ cout << "Point en (" << x << "," << y << ")\n";}
};
int main(){Point tp[] = {2,Point(),Point(3),Point(4,5)};for(int i=0 ; i < sizeof(tp)/sizeof(tp[0]) ; i++)
tp[i].afficher();system("PAUSE");
}
Tableau d'objets
• Lors de l'allocation mémoire par new[] leconstructeur par défaut est appelé
– le delete[] invoquera le destructeur
…tableau_objets.cpp
antislashn.orgC vers C++ 97
…int main(){
int NB = 5;
Point *tp2 = new Point[NB];
delete [] tp2;}…
Liste d'initialisation
• C++ apporte un nouveau mécanismed'initialisation des membres d'une classe par unconstruteur
– la liste d'initialisation
– syntaxe :– syntaxe :nom_classe(liste_parametres) : liste_initialisateurs {corps}
– l'ordre d'initialisation est celui dans lequel lesmembres apparaissent dans la classe et non pasl'ordre dans la liste
antislashn.orgC vers C++ 98
Liste d'initialisation
• Exemple (extrait)class A{
int i;double d;char c;
public :A(int k) : i(k), d(18.06), c('a') {};
};
liste-initialisation-1.cpp
– l'appel du constructeur A a(20); initialisera lesmembres à
• i == 20
• d == 18.06
• c == 'a'
antislashn.orgC vers C++ 99
Liste d'initialisation
• La liste d'initialisation est utilisée pourl'initialisation d'une instance de classe qui elle-même comporte un objet d'une autre classe.
• Dans l'exemple suivant :
antislashn.orgC vers C++ 100
class A{int i;
public :A() {i=0;}A(int k) {i=k;}
};
class B{int i;A a;
public :B() {i=0;}
};
Liste d'initialisation
• Lors d'une déclaration B b; le compilateur va :
– allouer l'espace pour b
– initialiser le membre a en appelant le constructeur pardéfaut A()
– initialiser le reste de b en appelant le constructeur par– initialiser le reste de b en appelant le constructeur pardéfaut B()
• Comment fixer une valeur à l'instance a ?• sans que le compilateur appelle plusieurs fois le
constructeur A()
– utiliser une liste d'initialisation
antislashn.orgC vers C++ 101
Liste d'initialisation
• Exemple (extrait)
– en rencontrant a(20) le compilateur va initialiser a.ien invoquant le constructeur A(20)
class A{int i;
public :
• La liste d'initialisation permet d'optimiser le code
antislashn.orgC vers C++ 102
public :A() {i=0;}A(int k) {i=k;}
};
class B{int i;A a;
public :B() : a(20) {i=0;}
};
Liste d'initialisation
• Initialisation d'une propriété constant ouréférence
– seule la liste d'initialisation permet d'initialiser cespropriétés
antislashn.orgC vers C++ 103
int j = 3;class A{
const int x;int &y;
public :A() : x(7), y(j) {}A(int k) {x = k;}
};
Illégal car x est constantet y est une référence
A(int k):x(k),y(j) {}
OK, liste d'intialisation
C++11 – Délégation de constructeur
• En C++ un constructeur ne peut pas appeler unautre constructeur de cette même classe
– duplication potentielle de code
– utilisation d'une méthode privée pour factoriser lecodecode
• C++11 permet à un constructeur de déléguer lecréation d'une instance à un autre constructeur
antislashn.orgC vers C++ 104
C++11 – Délégation de constructeur
• Exemple de code
class Point{int x;int y;
antislashn.orgC vers C++ 105
public :Point(int x, int y):x(x),y(y){}Point(int xy):Point(xy,xy){}
};
Opérateur de conversion
• Un constructeur peut être appelé pour effectuerune conversion de type
• exemple : Point p = (Point)6.3;
– ceci ne permet que les conversions dont le type cibleest la classe elle-mêmeest la classe elle-même
– il est possible de définir un opérateur de conversiondans une classe
• syntaxe : operator type () {…}– le type retourné dans le code doit correspondre au type redéfini
– pas d'indication du type retourné
• il sera implicitement appelé chaque fois qu'une conversionsera nécessaire
antislashn.orgC vers C++ 106
Opérateur de conversion
• Exempleclass Point{
int x,y;public:
Point(int x, int y) {this->x = x; this->y = y; }
operator int() {return x+y;}};
définition de la conversion
Point-8.cpp
antislashn.orgC vers C++ 107
int main(){
Point p = Point(2,3);cout << p*2 << endl;system("PAUSE");
}
vers int
invocation de la conversionvers int
Objets constants
• Si un objet est déclaré constant, les fonctionsmembres ne sont plus utilisables
– les fonctions membres doivent être déclarées const
• fait partie de la signature
antislashn.orgC vers C++ 108
class X{
int i;public :
X(int i) {this->i = i;}int doubler() const {return i*2;}
};
int main(){
const X x(3);cout << x.doubler() << endl;system("PAUSE");
}
objet-constant.cpp
Propriété constante
• Une propriété peut-être déclarée const
– comment l'initialiser ?
• Membre de classe non statique et constant
– initialisation par une liste d'initialisationinitialisation par une liste d'initialisation
antislashn.orgC vers C++ 109
class X{
const int i;public :
X(int j) : i(j) {}int doubler() const {return i*2;}
};
liste d'initialisation
Propriété constante
• Membre de classe statique et constant
– initialisation au moment du chargement duprogramme
class X{
objet-constant.cpp
antislashn.orgC vers C++ 110
{static const int i;
public :X() {}int doubler() const {return i*2;}
};const int X::i = 3;int main(){
const X x;cout << x.doubler() << endl;system("PAUSE");
}
initialisation au chargementdu programme
Surcharge des opérateurs
• C++ permet de surcharger les opérateurs– par exemple utiliser l'opérateur + pour "additionner" deux
instances de la classe Point
– il est impossible de redéfinir les opérations prédéfinies en C++
– on ne peut pas créer de nouveaux opérateurs
– les opérateurs suivants ne peuvent pas être surchargés– les opérateurs suivants ne peuvent pas être surchargés. :: ?: sizeof .*
– les règles de précédences et d'associativités sont conservées
– la syntaxe de la surcharge de certains opérateurs est soumise àdes règles spécifiques
• affectation = appel de fonction () indexation [] accès ->
• ++ et -- doivent tenir compte des formes préfixées et suffixées
antislashn.orgC vers C++ 111
Surcharge des opérateurs
• Syntaxe générale pour la surcharge d'unopérateur :
– type operator op(types des opérandes);
• ou op est l'opérateur à surcharger
• Surcharge au niveau global• Surcharge au niveau global
– définition en dehors de la classe
– l'appel est équivalent à operator+(p1,p2);
antislashn.orgC vers C++ 112
Point operator+(Point &p1, Point &p2){
int x = p1.getX() + p2.getX();int y = p1.getY() + p2.getY();return Point(x,y);
}
Surcharge des opérateurs
• De manière générale, si un opérateur est défini auniveau de la classe il attend un paramètre demoins que le nombre d'opérandes
– exemplePoint-9.cpp
antislashn.orgC vers C++ 113
class Point{int x,y;
public:Point(int x, int y) {this->x = x; this->y = y; }void afficher(){ cout << "Point en (" << x << "," << y << ")\n";}Point operator +(Point &p){ return Point(x + p.x,y + p.y); }Point operator-(){ return Point(-x, -y);}
};int main(){
Point p1(2,3);Point p3 = -p1;p3.afficher();
}
opérateur binaire +
opérateur unaire -
Point-9.cpp
Surcharge des opérateurs
• Surcharge au niveau de la classe
– définition dans la classe
– l'objet de classe qui invoque est le membre de gauche
– l'appel est équivalent à p1.operator+(p2);
antislashn.orgC vers C++ 114
class Point{int x,y;
public:Point(int x, int y) {this->x = x; this->y = y; }void afficher(){ cout << "Point en (" << x << "," << y << ")\n";}Point operator +(Point &p){
return Point(x + p.x,y + p.y);}
};
Surcharge des opérateurs
• Surcharge des opérateurs ++ et --
– la définition des opérateurs préfixés est standard
– la définition des opérateurs suffixés s'effectue enajoutant un int comme paramètre supplémentaire àla signaturela signature
antislashn.orgC vers C++ 115
class Point{int x,y;
public:Point(int x, int y) {this->x = x; this->y = y; }void afficher(){ cout << "Point en (" << x << "," << y << ")\n";}Point &operator++() { ++x;++y; return *this;}Point &operator++(int) { x++;y++; return *this;}
};
Point-9.cpp
ATTENTION : code nonfonctionnel
Surcharge des opérateurs
• Surcharge de l'opérateur d'affectation =
– par défaut fait une copie de surface de la classeclass Tableau{
int *tab; int taille;public:…
Tableau &operator=(const Tableau &t){if(this != &t)
{
t correspondra à t1
antislashn.orgC vers C++ 116
{delete [] tab;taille = t.taille; tab = new int[taille];for(int i=0 ; i<taille ; i++) tab[i] = t.tab[i];
}return *this;
} …};int main(){
Tableau t1(5);Tableau t2;for(int i=0 ; i<5 ; i++) t1.set(i,i);t2 = t1;
…}
appel de operator=Attention :Tableau t2 = t1; aurait appelé leconstructeur de copie
t2 est l'objet sur qui estinvoqué operator=()
operateur-affectation.cpp
Surcharge des opérateurs
• Surcharge de l'opérateur d'indexation []
– ne peut qu'être qu'un membre de classe
– considéré comme un opérateur binaire
• x[y] est interprété comme x.operator[](y)
– dans une expression telle que– dans une expression telle que• x[i] = y[i] + 1;
• il faut que l'affectation se fasse sur x[i], il faut donc queoperator[] renvoie une lvalue, ce qui est fait en renvoyantune référence
– sinon erreur à la compilation (pas une lvalue)
antislashn.orgC vers C++ 117
Surcharge des opérateurs
• Exemple de surcharge de l'opérateur [] (extrait)
class Tableau{int *tab;int taille;
public:...
int &operator[](int i){return tab[i];}
antislashn.orgC vers C++ 118
{return tab[i];}...};
int main(){
Tableau t1(5);Tableau t2;Tableau t3(1);
...t3[0] = t1[1] + t2[3];
...}
renvoie une référence verstab[i]
affectation possible car uneréférence est renvoyée
operateur-crochets.cpp
Surcharge des opérateurs
• Surcharge de l'opérateur d'appel de fonction ()
– nommé aussi foncteur ou objet fonction
– uniquement en tant que fonction d'une classe
– opération binaire
est interprété comme• c(x,y) est interprété comme c.operator()(x,y)
• prototype de la formetype operator() (paramètres);
– ne pas confondre avec l'opérateur de conversion
• rappel plus loin
antislashn.orgC vers C++ 119
Surcharge des opérateurs
• Exemple de foncteurs
class Inferieur{public:
bool operator()(int i, int j) { return i < j; }bool operator()(char a, char b) { return a < b; }bool operator()(char *s1, char *s2) {return strcmp(s1,s2) < 0; }
};
antislashn.orgC vers C++ 120
int main(){
Inferieur inf;cout << inf(1,2) << endl;cout << inf('z','a') << endl;cout << inf("aa","bb") << endl;system("PAUSE");
}foncteur.cpp
Surcharge des opérateurs
• Opérateur de conversion – rappel• syntaxe : operator type () {…}
– le type retourné doit correspondre au type redéfini
• il sera implicitement appelé chaque fois qu'une conversionsera nécessaire
antislashn.orgC vers C++ 121
class Point{int x,y;
public:Point(int x, int y) {this->x = x; this->y = y; }
operator int() {return x+y;}};
int main(){
Point p = Point(2,3);cout << p*2 << endl;system("PAUSE");
}
définition de la conversionvers int
invocation de la conversionvers int
Surcharge des opérateurs
• Les surcharges utilisables et leurs syntaxes sontrésumés sur le site Wikipedia– http://en.wikipedia.org/wiki/Operators_in_C_and_C++
antislashn.orgC vers C++ 122
C++11 – Rvalue Reference
• Une lvalue est une expression possédant un nomet qui reste en mémoire un certain temps– une variable est une lvalue
• Une rvalue n'a pas de nom et ne persiste pas– un entier littéral n'a pas de nom et sa portée est très– un entier littéral n'a pas de nom et sa portée est très
courte
– valeur retour de fonction
• Les rvalue references prennent en charge lasémantique de déplacement– syntaxe : &&
antislashn.orgC vers C++ 123
C++11 – Rvalue Reference
• Introduction d'une sémantique de déplacement(move)– en C++ il n'y a pas de manière générique de déplacer
un objet• si une fonction retourne un objet de taille importante, celui-
ci est copié dans une zone temporaire avant d'être à• si une fonction retourne un objet de taille importante, celui-
ci est copié dans une zone temporaire avant d'être ànouveau copié vers la zone où le résultat de la focntion estaffecté
– C++11 ajoute les Rvalues Reference• permet d'appeler la fonction "MoveFrom" à la place du
constructeur de copie si la copie correspond à undéplacement
antislashn.orgC vers C++ 124
C++11 – Constructeur de déplacement
• Extrait de codeclass MyContainer{
int nSize;char* pString;
public:MyContainer(MyContainer&& s){
moveIt(*this, s);}
antislashn.orgC vers C++ 125
}protected:
static void moveIt(MyContainer& tgt, MyContainer& src){cout << "Moving " << src.pString << endl;tgt.nSize = src.nSize;tgt.pString = src.pString;src.nSize = 0;src.pString = nullptr;
}...}
C++11 – Opérateur de déplacement
• Extrait de codeclass MyContainer{
int nSize;char* pString;
public:MyContainer& operator=(MyContainer&& s){
delete pString;moveIt(*this, s);return *this;
antislashn.orgC vers C++ 126
return *this;}
protected:static void moveIt(MyContainer& tgt, MyContainer& src){
cout << "Moving " << src.pString << endl;tgt.nSize = src.nSize;tgt.pString = src.pString;src.nSize = 0;src.pString = nullptr;
}...}
C++11 - Sémantique de déplacement
• Par rapport aux constructeur et opérateur decopie – extrait de code...public:
MyContainer(const MyContainer& s){copyIt(*this, s);
}MyContainer& operator=(MyContainer& s){
antislashn.orgC vers C++ 127
MyContainer& operator=(MyContainer& s){delete pString;copyIt(*this, s);return *this;
}protected:
static void copyIt(MyContainer& tgt,const MyContainer& src){cout << "Copying " << src.pString << endl;delete tgt.pString;tgt.nSize = src.nSize;tgt.pString = new char[tgt.nSize];strncpy(tgt.pString, src.pString, tgt.nSize);
}...
C++11 - Sémantique de déplacement
• Fonction utilitaires de la bibliothèque utility
– std::move()
• retourne une référence à une rvalue– fonction de transtypage
• prend pour paramètre une référence à une lvalue ou une• prend pour paramètre une référence à une lvalue ou unervalue
– std::forward()
• fait suivre une variable– retourne une lvalue reference si la variable est une lvalue reference
– retourne une rvalue reference si la variable est une rvaluereference
antislashn.orgC vers C++ 128
Les patrons
• Si plusieurs fonctions sont définies de la mêmefaçon et ne diffèrent que par les typesd'arguments, le développeur doit créerl'ensemble des fonctions
– en C on peut définir une macro préprocesseur
– le C++ fournit un mécanisme de patrons (templates)de fonction
• cette méthode s'étend aux classes
antislashn.orgC vers C++ 129
int max(int a, int b) { return (a>b) ? a : b ; }double max(double a, double b) { return (a>b) ? a : b ; }
#define MAX(a,b) ((a)>(b)) ? a : b
Patron de fonction
• Les types des arguments ne sont pas fixés et sontconsidérés eux-mêmes comme des paramètres– syntaxe
• template<typename parametre[,…]> définition_fonction
– la fonction max devient– la fonction max devient
– le compilateur va générer le code des fonctions entenant compte des appels
• si une fonction du même nom avec les bons types deparamètre existe déjà, le compilateur l'utilisera
– class peut être utilisé au lieu de typename
antislashn.orgC vers C++ 130
template <typename T> T max(T &a,T &b) { return (a>b) ? a : b ; }
Patron de classe
• Il peut arriver que plusieurs classes soientdéfinies de manières identiques, aux types près
– un patron de classe peut alors être utilisé
– syntaxe :• template <typename parametre[,…]> class nom_class{…}• template <typename parametre[,…]> class nom_class{…}
antislashn.orgC vers C++ 131
template <typename T> class Tableau{T tab[2];
public:Tableau(T x,T y) {tab[0]=x;tab[1]=y;}void afficher(){ cout << tab[0] << "\t" << tab[1] << endl;}
};int main(){
Tableau<int> t1(1,2);Tableau<char> t2('a','z');t1.afficher();t2.afficher();
}
génération des classes enprécisant le type
template-classe.cpp
Patron de classe
• Le compilateur générera les classes nécessaires
• Un patron de classe est entièrement codé dans lefichier .h– on ne peut pas pré-compiler un template
– pas de fichier .cpp– pas de fichier .cpp
• Si les déclarations et définitions sont séparées lenom de la méthode doit être complètementqualifié– dans le même fichier .h (pas de .cpp)
– les méthodes ne sont pas inline
antislashn.orgC vers C++ 132
Patron de classe
• Déclarations et définitions séparées
template <typename T> class Tableau{T tab[2];
public:Tableau(T x,T y) {tab[0]=x;tab[1]=y;}void afficher();
};
antislashn.orgC vers C++ 133
};
template<typename T> void Tableau<T>::afficher(){ cout << tab[0] << "\t" << tab[1] << endl;}
Patron de classe
• Il est possible de préciser un paramètre templatepar défaut
template <typename T, typename Y=int> class Toto{T t;Y y;
};
type par défaut
antislashn.orgC vers C++ 134
};
int main(){Toto<int> t1;Toto<double,double> t2;
}
équivalent à Toto<int,int>
typename
• typename est utilisé pour introduire un typegénérique– class peut aussi être utilisé
• typename sert aussi à introduire les identificateursde types inconnus dans les templatesde types inconnus dans les templates
antislashn.orgC vers C++ 135
class A{public:
typedef int Y;};
template <class T> class X{
typename T::Y i;};
int main(){X<A> x;
};
type définit dans la classe A
la classe X suppose que letype générique T définit untype Y
typename.cpp
Membres statiques
• Donnée statique– la classe contient la déclaration de la donnée statique
– la définition de la donnée statique s'effectue au niveau global
class Point{int x,y;
public:déclaration
membres-static.cpp
antislashn.orgC vers C++ 136
public:static int nombre;Point(int x, int y) { this->x = x ; this->y = y; nombre++;}Point(){x=y=0; nombre++;}~Point() {nombre--;}void afficher(){cout << "Point " << nombre << " en (" << x << "," << y << ")\n";}
};int Point::nombre=0;int main(){
Point p1;Point p2(5,6);p1.afficher();p2.afficher();system("PAUSE");
}
définition et initialisation
Membres statiques
• Fonction statique
– n'a pas accès aux membres non statiques
– le pointeur this n'est pas passé à la fonction statiqueclass Point{
int x,y;static int nombre;
déclaration (privée)
antislashn.orgC vers C++ 137
static int nombre;public:
Point(int x, int y) { this->x = x ; this->y = y; nombre++;}Point(){x=y=0; nombre++;}~Point() {nombre--;}static int getNombre() {return nombre;}void afficher(){ cout << "Point " << nombre << " en (" << x << "," << y << ")\n";}
};int Point::nombre=0;int main(){
Point p1;Point p2(5,6);
cout << Point::getNombre() << endl;system("PAUSE");
}
fonction d'accès statique
appel de la fonction statique
membres-static.cpp
Héritage
• Syntaxe de baseclass classe_derivee : type_protection classe_base {…};
– le type de protection définit l'accessibilité dans laclasse dérivée des membres de la classe de base
• on ne peut que restreindre l'accessibilité• on ne peut que restreindre l'accessibilité
• dans tous les cas les membres privés de la classe de base nesont pas accessibles dans la classe dérivée
– public : on conserve les accessibilités
– protected : les membres publiques et protégés de la classe debase deviennent protégés dans la classe dérivée
– private : les membres publiques et protégés de la classe de basedeviennent privés dans la classe dérivée
antislashn.orgC vers C++ 138
Héritage
• La classe dérivée hérite de l'ensemble desmembres de la classe de base
– les membres privés sont hérités mais ne sont pasaccessible par la classe dérivée
• principe d'encapsulation, il faut fournir des méthodes• principe d'encapsulation, il faut fournir des méthodespubliques pour accéder aux propriétés privées
– il y réunion des membres
• chaque objet de la classe dérivée contient un objet de laclasse de base
antislashn.orgC vers C++ 139
Héritage
• Empreinte mémoire
– la classe B dérive de la classe Aclass A{
char ta[256];};
class B : public A{
heritage-1.cpp
antislashn.orgC vers C++ (version v1.1) 140
class B : public A{char tb[256];
};
int main(){
cout << "Encombrement de A : " << sizeof(A) << endl;cout << "Encombrement de B : " << sizeof(B) << endl;
}
char ta[256] char ta[256]
char tb[256]instance de A
instance de B
sous instance A
Héritage
• Exemple
class Vehicule{char *marque;
public:Vehicule(){marque = "INCONNU"; }Vehicule(char * marque){this->marque = marque;}void afficher() {cout << "Vehicule - marque : "<<marque<<endl;}
};
Vehicule-1.cpp
antislashn.orgC vers C++ 141
};
class Voiture : public Vehicule{};
int main(){
Voiture v1;v1.afficher();system("PAUSE");
}
Voiture spécialise Véhicule
utilisation de la méthode dela classe de base
Héritage – sous-typage
• Conversion de classe dérivée en classe de base
– la conversion est implicite dès que cela est nécessaire
– la visibilité est alors réduite à la classe de base
class Voiture : public Vehicule{public:
Vehicule-1.cpp
antislashn.orgC vers C++ 142
public:void rouler(){cout << "La voiture " << getMarque() << " roule\n";}
};
int main(){
Voiture v1;v1.afficher();v1.rouler();Vehicule v2 = v1;v2.rouler();system("PAUSE");
}
accesseur défini dansVehicule pour la propriétéprivée de Vehicule
OK : v1 est de type Voiture
ERREUR : v2 est de typeVehicule
Héritage – forçage vers la classe dérivée
• Il est illicite de convertir un type de base vers untype dérivé.
• Un pointeur sur la classe de base peut êtreconverti en un pointeur vers la classe dérivée
– conversion explicite
– n'a de sens que si l'objet concret pointé par lepointeur est bien du type de la classe dérivée
antislashn.orgC vers C++ 143
Héritage – forçage vers la classe dérivée
• Exempleclass Vehicule{
char *marque;public:
Vehicule(){marque = "INCONNU"; }Vehicule(char * marque){this->marque = marque;}void afficher() {cout << "Vehicule - marque : "<<marque<<endl;}char * getMarque(){ return marque;}
};
Vehicule-1.cpp
antislashn.orgC vers C++ 144
class Voiture : public Vehicule{public:
void rouler(){cout << "La voiture " << getMarque() << " roule\n";}};
int main(){
Voiture *vo1 = new Voiture();Vehicule *ve1 = vo1;Voiture *vo2;vo2 = (Voiture *) ve1;vo2->rouler();system("PAUSE");
}
OK car ve1 pointe vers unobjet concret Voiture
sous-typageve1 de type Vehicule pointevers un objet concret detype Voiture
Héritage
• L'accès à un membre peut être désignés par son nom ou par son nomcomplètement qualifié.– si le nom du membre de classe à la même nom dans la classe de base et la
classe dérivée, la référence au membre de la classe de base passe par lenom qualifié
class A{public:
heritage-2.cpp
antislashn.orgC vers C++ 145
public:void f() { cout << "A::f()\n";}
};
class B : public A{public:
void f() { cout << "B::f()\n";}};
int main(){
A a; B b;a.f(); b.f();b.A::f();system("PAUSE");
}
accès à la fonction de laclasse de base
Héritage – les constructeurs
• Chaque fois qu'un constructeur d'une classedérivée est appelé, le constructeur de la classe debase est d'abord appelé
– deux cas sont à considérés
• le cas général• le cas général
• le cas du constructeur de copie
antislashn.orgC vers C++ 146
Héritage – les constructeurs
• Cas général
– si un constructeur de la classe dérivée est appelé(autre que le constructeur de copie)
• le constructeur de la classe de base appelé est celui qui estprésent dans la liste d'initialisationprésent dans la liste d'initialisation
• s'il n'y a pas de liste d'initialisation, le constructeur pardéfaut de la classe de base est appelé
• si aucun constructeur n'est défini dans la classe dérivée, leconstructeur par défaut de la classe de base est appelé
antislashn.orgC vers C++ 147
Héritage – les constructeurs
• Exemple : cas généralclass A{public:
A(){ cout << "A()\n";}A(int i){ cout << "A(int i)\n";}
};
class B : public A{public:
heritage-3.cpp
antislashn.orgC vers C++ 148
public:B(){ cout << "B()\n";}B(int i):A(i){ cout << "B(int i)\n";}B(char c){ cout << "B(char c)\n";}
};
int main(){
B b;cout << endl;B c(1);cout << endl;B d('a');cout << endl;system("PAUSE");
}
Héritage – les constructeurs
• Cas du constructeur de copie– lorsqu'une classe ne possède pas de constructeur par
copie le compilateur en fournit un
– si la classe dérivée n'a pas de constructeur de copie, leconstructeur de copie (défini ou par défaut) de laconstructeur de copie (défini ou par défaut) de laclasse mère est appelé
– si la classe fille possède un constructeur de copie, leconstructeur de la classe mère appelé dépend de laliste d'initialisation
• si la liste est absente ou n'indique pas de constructeur pourla classe mère, c'est le constructeur par défaut de la classemère qui est appelé
antislashn.orgC vers C++ 149
Héritage – les constructeurs
• Exemple : constructeur de copie
class A{public:
A(){ cout << "A()\n";}A(const A &a){ cout << "A(const A &a)\n";}
};class B : public A{public:
B(){ cout << "B()\n";}
appel du constructeur pardéfaut de A
heritage-4.cpp
antislashn.orgC vers C++ 150
B(){ cout << "B()\n";}B(const B &b){ cout << "B(const B &b)\n";}
};class C : public A{public:
C(){ cout << "C()\n";}C(const C &c):A(c){ cout << "C(const C &c)\n";}
};int main(){
B b1;B b2 = b1;C c1;C c2 = c1;
}
appel du constructeur decopie de A
Héritage - template
• Un template peut hériter d'un autre template
• Une classe peut hériter d'un template
template <typename T> class X{T t;
};
heritage_template.cpp
antislashn.orgC vers C++ 151
};
template <typename U, typename V> class Y : public X<U>{V u;
};
class V : public X<float>{};
int main(){Y<int,double> y;V v;
}
Dérivation et opérateur d'affectation
• Similaire au constructeur de copie
– soit b2 = b1; où b1 et b2 sont des instancesd'une classe B dérivée de A
– si l'opérateur d'affectation de B n'a pas été redéfini,l'opérateur d'affectation de A est appelél'opérateur d'affectation de A est appelé
– si l'opérateur d'affectation de B a été redéfini,l'opérateur d'affectation de A n'est pas appelé
• toutes les affectations de la partie de la classe B dépendantde A doivent être codée explicitement
antislashn.orgC vers C++ 152
Dérivation et opérateur d'affectationclass A{public:
A(){cout << "++ CONSTRUCTEUR A()" << endl;}A(const A &a){cout << "++ CONSTRUCTEUR COPIE A(const A &a)" << endl;}A &operator=(const A &a) {
cout << "=> OPERATOR=(const A &a) de A" << endl;return *this;}
};
class B : public A{public:
B(){cout << "++ CONSTRUCTEUR B()" << endl;}B(const B &b){cout << "++ CONSTRUCTEUR COPIE B(const B &b)" << endl;}
heritage-5.cpp
antislashn.orgC vers C++ 153
B &operator=(const B &b) {A *pa1 = this;A *pa2 = const_cast<B*> (&b);*pa1 = *pa2;cout << "=> OPERATOR=(const B &b) de B" << endl;return *this;}
};
int main(){
B b1;cout << "============================" << endl;B b2;cout << "============================" << endl;b1 = b2;cout << "============================" << endl;
}
affectation de la partie Ade l'instance
Polymorphisme
• Un des principes du polymorphisme est qu'une classe dérivéeest compatible avec sa classe de base.– là où une Figure est prévue on doit pouvoir y substituer un Carre
• tous les services offerts par une Figure sont offert par un Carre– sous réserve des droits d'accès
• la conversion d'une classe vers sont type de base est une conversionstandard
Carre c;Figure f = c;
antislashn.orgC vers C++ 154
class Figure{public:
void afficher(){cout << "A CODER" << endl;
}};
class Carre : public Figure{public:
void afficher(){cout << "AFFICHAGE D'UN CARRE" << endl;
}};
Figure-1.cpp
Polymorphisme
• Selon que l'on applique cette conversion sur des objets oudes pointeurs la conversion est effectuée différemment
• Convertir un objet Carre vers un objet Figure revient à luienlever les membres qui ne font pas partie de Carre– il y a perte effective d'information
– peut être vu comme l'appel implicite d'une méthode de– peut être vu comme l'appel implicite d'une méthode deconversion de Carre vers Figure
antislashn.orgC vers C++ 155
Carre c;Figure f = c;
Figure
Carre
Figure
instance c
static_cast<Figure> (c)
Polymorphisme
• Convertir un pointeur vers Carre vers un pointeurvers Figure ne fait perdre aucune information
– l'instance n'offre que les services de Figure, mais il necesse pas d'être un Carre avec tous ces membres
antislashn.orgC vers C++ 156
Carre c;Figure *pf = &c; Figure
Carre
pf static_cast<Figure *> (&c)
Polymorphisme
• Exemple
– seul l'appel de l'affichage d'un Carre par un objet detype Carre fonctionne !!!
– il faut distinguer le type statique et le type dynamique
antislashn.orgC vers C++ 157
int main(){
Carre c;Figure f1;Figure f2 = c;Figure *f3 = &c;Figure &rf = c;c.afficher();f1.afficher();f2.afficher();f3->afficher();rf.afficher();
}
Figure-1.cpp
Polymorphisme
• Par défaut la détermination du membre accédé à travers unpointeur ou une référence est fait durant la compilation– donc par le type statique du pointeur ou de la référence– le type statique d'une expression est connu à la compilation– le type dynamique est déterminé par la valeur courante de
l'expression• peut évoluer durant l'exécution• peut évoluer durant l'exécution
• Par défaut la détermination du membre à accéder à travers unpointeur ou une référence se fait durant la compilation– c'est-à-dire d'après le type statique du pointeur ou de la référence
• Pour que la détermination soit effectuée dynamiquement il fautdéclarer les fonctions virtuelles– quand déclarer une fonction virtuelle ?
• si une fonction est redéfinie dans les classes dérivées• si une fonction est appelée à travers des pointeurs ou références
antislashn.orgC vers C++ 158
Fonctions virtuelles
• Types statiques et dynamiquesclass B {};class D : public B {};
int main(){
D d;B b = d;B *pb = &d;
– le type statique de *pb et de rb est B
• analyse du programme, déterminé à la compilation
– le type dynamique de *pb et de rb est D
antislashn.orgC vers C++ 159
B *pb = &d;B &rb = d;
}
Fonctions virtuelles
class Figure{public:
virtual void afficher(){cout << "A CODER" << endl;
}};
class Carre : public Figure{public:
void afficher(){cout << "AFFICHAGE D'UN CARRE" << endl;
}
fonction virtuelleFigure-2.cpp
antislashn.orgC vers C++ 160
}};
int main(){
Carre c;Figure f1;Figure f2 = c;Figure *f3 = &c;Figure &rf = c;c.afficher();f1.afficher();f2.afficher();f3->afficher();rf.afficher();
}
f1 et f2 sont desinstances de Figure
Perte des informationspropre à Carre
Fonctions virtuelles
• La création d'une classe polymorphe implique l'initialisationd'un pointeur vptr vers une vtable de la classe
• Un appel comme f3->afficher()– en absence de fonction virtuelle aurait été traduit parFigure::afficher(f3)
– avec une fonction virtuelle il est traduit comme(*f3->vptrFigure[0])(f3)(*f3->vptrFigure[0])(f3)
• [0] car affiche() est la première fonction virtuelle
antislashn.orgC vers C++ 161
propriétés de Figure
vprtFigure
instance de Figure
&A::affiche
vtable de Figure
autres méthodesvirtuelles
Fonctions virtuelles
• Un objet n'est pas typé tant qu'il n'est pascomplètement construit
– un constructeur ne peut pas être virtuel
– l'appel d'une fonction virtuelle dans un constructeurn'a pas toujours l'effet escomptén'a pas toujours l'effet escompté
• Le destructeur peut-être virtuel
– ATTENTION : si le destructeur n'est pas virtuel ledestructeur de la classe fille ne sera pas appelé
antislashn.orgC vers C++ 162
Destructeur virtuel
class A{public:
A(){ cout << "++ CONSTRUCTEUR A()" << endl;}~A(){ cout << "-- DESTRUCTEUR ~A()" << endl;}
};
class B:public A{public:
B(){ cout << "++ CONSTRUCTEUR B()" << endl;}~B(){ cout << "-- DESTRUCTEUR ~B()" << endl;}
};
destructeur-virtuel.cpp
Destructeur nonvirtuel
antislashn.orgC vers C++ 163
};
int main(){A *pa = new B();delete pa;
}
Pas d'appel audestructeur de B
Classe abstraite
• Des fonctions peuvent être purement virtuelles
– pas d'implémentation fournie
– présente le vocabulaire de base
– syntaxe :virtual void nom_fonction() = 0;
• Une classe qui comporte au moins une fonctionvirtuelle pure est une classe abstraite
– pas de création d'instance
– une classe abstraite pure ne comporte que desfonctions virtuelles pures
antislashn.orgC vers C++ 164
Classe abstraite
• Exemple class Figure{public:
virtual void afficher() =0 ;};
class Point : public Figure{int x,y;
public :Point(int x, int y){this->x = x, this->y = y;}void afficher(){ cout << "Point en (" << x << "," << y << ")\n"; }
};class Carre : public Figure{
classe abstraite
Figure-3.cpp
antislashn.orgC vers C++ 165
class Carre : public Figure{Point xy;int cote;
public:Carre(int x, int y, int cote):xy(x,y) {this->cote = cote;}void afficher(){ cout <<"Carre cote : " << cote << endl; }
};int main(){
Carre *c = new Carre(1,2,3);Point *p = new Point(8,9);c->afficher();p->afficher();
}
Héritage multiple
• En C++ une classe peut hériter de plusieursclasses de base
– lors de l'initialisation de la classe B, l'ordre d'appel desconstructeurs correspond à l'ordre de déclaration desclasses de baseclasses de base
antislashn.orgC vers C++ 166
class A1{
};
class A2{
};
class B : public A1, public A2{
};
Héritage multiple
• Si les classes A1 et A2 sont elles même dérivéesd'une même classe de base, des ambigüitéspeuvent apparaitre
– les classes virtuelles permettent de solutionner cesambigüitésambigüités
• Forçage de type
• les valeurs de pa1 et pa2 sont différentes
antislashn.orgC vers C++ 167
B *pb = new B;A1 *pa1 = pb;A2 *pa2 = pb;
Héritage multiple
• Les membres d'une classe possèdent une portée– par dérivation de classe ou imbrication d'une classe dans
une autre
– à chaque niveau de dérivation est associée une portée, etun nom défini à ce niveau masque le même nom défini àun niveau supérieurun niveau supérieur
– ainsi avec l'héritage multiple il peut arriver qu'un mêmenom de fonction soit utilisé dans deux classes de base
• erreur de compilation lors de l'appel de la fonction
• le développeur peut préciser la classe de base utilisée
• certains compilateur permettent de mettre en place une clauseusing afin de changer la portée des fonctions
– il faut que les fonctions héritées aient des signatures différentes
antislashn.orgC vers C++ 168
Héritage multiple
• Exempleclass A1{
int i;public:
void f(int i) { cout << "A1::f(int)\n"; }};
class A2{int j;
heritage-multiple-1.cpp
antislashn.orgC vers C++ 169
int j;public:
void f(char c) { cout << "A2::f(char)\n"; }};
class B : public A1, public A2{using A1::f;using A2::f;
};
int main(){
B b;b.f(1);
}
clauses 'using' pour changerla portée des fonctions
appel de la fonction sansavoir besoin de préciser laclasse de base : b.A1::f(1);
Héritage multiple
• Empreinte mémoireclass A1{
char ta1[100];};
class A2{char ta2[100];
};
class B : public A1, public A2{char tb[100];
heritage-multiple-2.cpp
antislashn.orgC vers C++ 170
char ta1[100]
char ta2[100]
instance de B
sous instance A1
char tb[100];};
int main(){
cout << "Encombrement pour A1 : " << sizeof(A1) << endl;cout << "Encombrement pour A2 : " << sizeof(A2) << endl;cout << "Encombrement pour B : " << sizeof(B) << endl;
}
char tb[100]
sous instance A2
Héritage multiple
• Soit le schémas d'héritageclass A {...};class B1 : public A {...};class B2 : public A {...};class C: public B1, public B2 {...};
b1
aa
b2
c
– une instance de C comprend alors deux objets A
• occupation inutile de mémoire
• complication du codage
– la déclaration virtuelle de A dans la définition de B1 etB2 résout le problème
• il n'y aura qu'un objet a
antislashn.orgC vers C++ 171
Héritage multiple
• Sans déclaration virtual
class A{char a[100];
};
class B1:public A{char b1[100];
};
char a[100]
instance de A
char a[100] char a[100]
heritage-multiple-3.cpp
antislashn.orgC vers C++ 172
class B2:public A{char b2[100];
};
class C:public B1,public B2{char c[100];
};
char b1[100]
instance de B1
char b2[100]
instance de B2
char b1[100]
char a[100]
char b2[100]
instance de C
char c[100]
char a[100]
sous instance A de B1
sous instance A de B2
sous instance B1
sous instance B2
Héritage multiple
• Le code devient alorsclass A {...};class B1 : virtual public A {...};class B2 : virtual public A {...};class D: public B1, public B2 {...};
b1
a
b2
d
– le mécanisme d'appel des constructeurs est alorsmodifié
• le compilateur ignore les appels aux constructeurs de A quifigureraient dans une liste d'initialisation de B1 et B2
• on peut appeler les constructeurs de A dans une listed'initialisation de D
antislashn.orgC vers C++ 173
Héritage multiple
• Avec déclaration virtualclass A{
char a[100];};
class B1:virtual public A{char b1[100];
};
char a[100]
instance de A
char b2[100]
4 octets
char b1[100]
4 octets
antislashn.orgC vers C++ 174
class B2:virtual public A{char b2[100];
};
class C:public B1,public B2{char c[100];
};
instance de C
sous instance A
sous instance B1
sous instance B2
heritage-multiple-3.cpp
instance de B2
char a[100]
instance de B1
char a[100]
char b1[100]
char a[100]
4 octets
char b2[100]
4 octets
char c[100]
Classe – forme générale
• Forme générale
– un constructeur par défaut
• allocation de certaines parties de l'objet
– un destructeur
• désallocation des parties allouées dans le constructeur• désallocation des parties allouées dans le constructeur
– constructeur de copie
– opérateur d'affectation
antislashn.orgC vers C++ 175
class T{public:
T(…);T(const T&);~T();T& operator= (const T&);
};
Classe – forme générale
• Héritage et forme générale– classe de base T respectant la forme générale
• destructeur virtuel
• méthodes devant être redéfinies par les classes dérivées virtuelles
– classe dérivée U respectant la forme générale
antislashn.orgC vers C++ 176
class U :public T{public:
U(…);U(const U &x):T(x){
// recopie de la partie spécifique à U}~U();
U & operator=(const U & x){T *ad1 = this;T *ad2 = &x;*ad1 = ad2; // affectation de la partie héritée T// affectation de la partie non héritée
}};
Identification dynamique du type
• Le coût du polymorphisme est une indirectionsupplémentaire pour chaque appel de méthode– chaque objet à un encombrement supplémentaire
égal à la taille d'un pointeur, quelque soit le nombrede fonctions virtuellesde fonctions virtuelles
• Si un pointeur pointe sur un objet– on connait le type réellement pointé
• tout du moins le développeur le connait
– on connait le type du pointeur défini à la compilation
– il peut être souhaitable de voir l'objet pointé commel'objet concret, et non pas comme l'objet de base
antislashn.orgC vers C++ 177
Identification dynamique de classe
• Opérateur dynamic_cast
– syntaxe : dynamic_cast<type>(expression)
– permet la conversion d'une expression de typepointeur vers une autre
• si une classe de base A est dérivée en BA • si une classe de base A est dérivée en B– la conversion B* vers A* ne fait rien de plus que la conversion
standard
– la conversion A* vers B* n'a de sens que si le type concret pointéest bien de type B*
– l'opérateur dynamic_cast rend la conversion sure et portable
» rend l'adresse de l'objet si la conversion est possible
» renvoie NULL si la conversion n'est pas possible
antislashn.orgC vers C++ 178
A
B
Identification dynamique de classe
• Exemple sur dynamic_castclass A{
virtual void foo(){}};
class B1:public A{};class B2:public A{};
class B3{};
class C:public B1, public B2, protected B3{};
dynamic_cast.cpp
antislashn.orgC vers C++ 179
class C:public B1, public B2, protected B3{};
int main(void){
A *pa = new A;B1 *pb1 = new C;C *pc = new C;A &ra = *pa;// Vaut nullcout << "dynamic_cast<C *>(pa) : " << dynamic_cast<C *>(pa) << endl;// C dérive de B3 protected//cout << "dynamic_cast<B3 *>(pc) : " << dynamic_cast<B3 *>(pc) << endl;// Ambiguité : quel A ?//cout << "dynamic_cast<A *>(pc) : " << dynamic_cast<A *>(pc) << endl;cout << "dynamic_cast<C *>(pb1) : " << dynamic_cast<C *>(pb1) << endl;cout << "dynamic_cast<A *>(pb1) : " << dynamic_cast<A *>(pb1) << endl;cout << "dynamic_cast<B2 *>(pb1) : " << dynamic_cast<B2 *>(pb1) << endl;
}
ne passe pas à lacompilation
Identification dynamique de classe
• Opérateur typeid– permet de connaitre le véritable type d'un objet désigné par un
pointeur ou une référence– renvoie un objet de type type_info
• contient entre autre– une méthode name()
– les opérateur == et != pour la comparaison
antislashn.orgC vers C++ 180
int main(void){
D d;B &b = d;NV &nv = d;int i;B b1;
cout << typeid(b).name() << endl;cout << typeid(3.2).name() << endl;cout << typeid(nv).name() << endl;cout << typeid(d).name() << endl;cout << typeid(b1).name() << endl;
if(typeid(b)==typeid(d))cout << "type identique" << endl;
}
typeid.cpp
Pointeur sur membre de classe
• Il est courant de manipuler des fonctions autravers de pointeurs
– mécanisme du C
– transposé sur les classes en C++, cela revient àréférencer une fonction statique d'une classeréférencer une fonction statique d'une classe
antislashn.orgC vers C++ 181
class A{public:
static int doubler(int i) {return i*2;}};
int main(){
A a;int (*pf)(int);pf = A::doubler;cout << (*pf)(5) << endl;system("PAUSE");
}
pointeur versfonction
pointeur-membre-1.cpp
Pointeur sur membre de classe
• Pour un objet donné, il est toujours possible deréférencer par pointeur une donnée
– sous réserve de l'accessibilité
class A{public:
antislashn.orgC vers C++ 182
public:int i;int doubler(int i) {return i*2;}
};
int main(){
A a;int *pi = &a.i;
}
pointeur vers int
Pointeur sur membre de classe
• Mais il peut être utile de pouvoir manipuler desnotions plus abstraites– pointer sur une fonction membre non statique
– pointer sur une fonction de la classe ayant unargument de type int et retournant un doubleargument de type int et retournant un double
– pointer sur un champ de type int de la classe
• C++ met en place un syntaxe particulière pour cesnotions– syntaxe pouvant paraitre insolite
– le pointeur n'a pas son sens usuel : sa valeur n'est pasaccessible
antislashn.orgC vers C++ 183
Pointeur sur membre de classe
• Pointeur sur une donnée membre
– déclaration• type classe::*pointeur;
– initialisation• pointeur = &classe::donnee;• pointeur = &classe::donnee;
• Après l'initialisation le pointeur ne désigne pasd'adresse en mémoire
– il est associé à l'offset du champ dans l'objet
– il peut être utilisé ensuite sur un objet de la classe• objet.*pointeur;
antislashn.orgC vers C++ 184
Pointeur sur membre de classe
• Exemple de pointeur sur une donnée membre
using namespace std;
class A{public:
int i;A(int j){i=j;}
pointeur-membre-2.cpp
antislashn.orgC vers C++ 185
int doubler(int i) {return i*2;}};
int main(){
A a(20);int A::*pi = &A::i;cout << a.*pi << endl;system("PAUSE");
}
déclaration etinitialisation du pointeur
utilisation du pointeur
Pointeur sur membre de classe
• Pointeur sur une fonction membre– déclaration
• type_retour (class::*pointeur)(liste_type_arguments);
– initialisation• pointeur = &classe::fonction;
• Comme le cas précédent le pointeur ne contient• Comme le cas précédent le pointeur ne contientpas l'adresse– il ne peut être converti vers un pointeur vers fonction
au sens C
– il peut être utilisé par une instance de la classe• (objet.*pointeur)(liste_paramètres);
antislashn.orgC vers C++ 186
Pointeur sur membre de classe
• Exemple de pointeur sur une fonction membre
class A{public:
int i;A(int j){i=j;}int doubler(int i) {return i*2;}
};
pointeur-membre-3.cpp
antislashn.orgC vers C++ 187
int main(){
A a(20);A *pa = &a;int (A::*pf)(int) = &A::doubler;cout << (a.*pf)(56) << endl;cout << (pa->*pf)(56) << endl;system("PAUSE");
}
déclaration etinitialisation du pointeursur fonction membre
utilisation du pointeurvia l'instance
utilisation du pointeurvia un pointeur versl'instance
Les exceptions
• C++ définit un mécanisme de traitement deserreurs : les exceptions
• Une exception est levée par une instructionthrow
exception-1cpp
– un type quelconque peut être lancé dans l'exception
• possibilité de créer ses propres classes d'exception
antislashn.orgC vers C++ 188
void Point::exceptionPointNonValide(){
if(x<0 || y<0)throw "Point avec coordonnees negatives";
}
exception-1cpp
Les exceptions
• Un bloc try entoure le code susceptible de lancerune exception
• Un bloc catch permet de gérer l'exception
– peut être omis en fonction des compilateurs
• un gestionnaire par défaut est mis en place– termine le programme
– le type du paramètre du catch correspond au type del'exception levée
– plusieurs blocs catch peuvent être mis en place
• avec des signatures différentes
antislashn.orgC vers C++ 189
Les exceptions
• Exemple de traitement (extrait)
try{
Point p(-1,2);cout<<"tout c'est bien passe"<<endl;
}catch(char *m)
instruction susceptiblede lancer une exception
exception-1.cpp
antislashn.orgC vers C++ 190
{cout<<"ATTENTION : "<<m<<endl;
}catch(int m){
cout<<"Exception numero : "<<m<<endl;}
signature pour unpointeur vers char
signature pour un entier
Les exceptions
• Si l'exception n'est pas attrapée elle remonte à lafonction appelante
• Si l'exception remonte jusqu'au main alors lafonction terminate() est appelée
– possibilité de personnaliser en fournissant sa proprefonction à set_terminate
• Un catch peut aussi lever une exception
antislashn.orgC vers C++ 191
Les exceptions
• Une fonction peut indiquer le type d'exception qu'elle estsusceptible de lever– précise le contrat à l'intention des utilisateurs de la fonction
• si la fonction lance une exception non prévue la fonction unexpectedest alors appelée
– le comportement personnalisé en fournissant à la fonction set_unexpected sonpropre gestionnaire
– syntaxe :– syntaxe :en_tête_fonction throw(type, type,…)• si aucun type n'est précisé, cela indique que la fonction ne peut lancer
aucune exception• une fonction dont la clause throw(…) n'est pas précisé peut lever tout
type d'exception
– cette fonctionnalité n'est pas présente sur tous lescompilateurs
• le mécanisme des exceptions fonctionne mais pas le unexpected
antislashn.orgC vers C++ 192
Les exceptions
• Fonctions terminate et unexpected
– unexpected n'est pas supportée par tous lescompilateurs typedef void (*handler)();
handler set_terminate(handler);handler set_unexpected(handler);
antislashn.orgC vers C++ 193
void exceptionNonTraitee(){
cout << "ERREUR" << endl;exit(EXIT_FAILURE);
}int main(){
set_terminate(exceptionNonTraitee);Point p(-1,2);cout<<"tout c'est bien passe"<<endl;
}exception-2.cpp
Les exceptions
• Une exception est une valeur quelconque
• Les fonctions de la bibliothèque peuvent leverdes exceptions
– ces exceptions sont dérivées d'une classe commune,la classela classe exception
• 3 types dérivés directement ou indirectement– les exceptions : bad_exception, bad_cast, bad_typeid, …
– bad_alloc
– les runtime_error : range_error, overflow_error,underflow_error
antislashn.orgC vers C++ 194
Les exceptions
• Lors d'une exception les instructions placée entre lepoint où est lancée l'exception et celui où elle estattrapée sont abandonnées– cela ce traduit par la terminaison immédiate des fonctions
• la pile d'exécution est décapitée
• les espaces locaux sont perdus• les espaces locaux sont perdus
• les allocations ne sont pas libérées
– C++ garanti que les destructeurs des objets locaux auxfonctions sont appelés
• on peut alors utiliser une classe spécifique gérant les pointeurs etles allocations / désallocations mémoire
– cf. les smart pointer
antislashn.orgC vers C++ 195
Les exceptions
• Flux normal d'appel méthode A
méthode B méthode C
antislashn.orgC vers C++ 196
• Flux exceptionnelméthode A
méthode B méthode C
levéed'exception
code nonexécuté
Espaces de noms
• Un espace de noms permet d'éviter les collisionsde nommage sur des bibliothèques différentes
– les entités de la bibliothèque standard appartiennentà l'espace de noms std
espace de nom utilisé par
antislashn.orgC vers C++ 197
using namespace std;
namespace perso{class X{};class Y{};
}
int main(){
perso::X x;}
espace de nom utilisé pardéfaut
définition d'un espace denoms
utilisation de la classe X
namespace.cpp
Espaces de noms
• Les espaces de noms peuvent être imbriqués
– exemples pour .h et .cpp#ifndef __POINT_H__#define __POINT_H__
namespace antislashn{namespace formes{
class Point
namespace antislashn{namespace formes{
Point::Point(int x){
…}
antislashn.orgC vers C++ 198
class Point{
private :int x,y;
public :void afficher();Point();Point(const Point &);Point(int);Point(int,int);
};}
}#endif
}
…void Point::afficher(){
…}
}
Espaces de noms
• Utilisation des namespaces imbriqués#include "Point.h"#include <iostream>
using namespace antislashn::formes;int main(){
Point p = (Point)8;p.afficher();
• Convention possible : utilisation des chemins desfichiers, façon "packages java"
antislashn.orgC vers C++ 199
Point p1 = p;
Point * pt = new Point(6);p.afficher();pt->afficher();delete pt;
::std::cout<<"FIN\n";}
Espaces de noms
• Utilisation partielle des espaces de nom– de manière générale
::[namespace::] identificateur::antislashn::formes::Point
[namespace::] identificateurformes::Pointformes::Point
• L'éventuel premier :: indique la région déclarativeglobale– une expression commençant par :: est interprétée
comme absolue
– une expression ne commençant pas par :: estinterprétée comme relative
antislashn.orgC vers C++ 200
Espaces de noms
• Aliasnamespace alias = espaceDeNoms;
– introduit un alias pour une espace de nommage donné• réduction d'un espace de noms particulièrement long
• paramétrage d'un espace de noms
• Espace anonyme• Espace anonyme– directive namespace sans nom
– identificateur unique pour chaque unité de compilation• équivaut à des déclarations statiques au niveau globale
• l'emploie des espaces de noms anonyme est préférable à celui duqualificateur static
– autres significations dans d'autres contextes : membres de classe,variables locales statiques
antislashn.orgC vers C++ 201
Bibliothèque standard
• Ensemble de librairies définies par la norme ISO– bibliothèque regroupée dans 32 fichiers d'en-tête
• support du langage
• diagnostics
• utilitaires généraux
• chaînes de caractères• chaînes de caractères
• localisation
• composants numériques
• flux d'entrée / sortie (IO Stream Library)
• Standard Template Library– conteneurs
– itérateurs
– algorithmes
antislashn.orgC vers C++ 202
Bibliothèque standard
• Sauf les macros et opérateurs new et delete, tousles éléments sont membres de l'espace standardstd, ou d'espaces imbriqués dans std
• Les éléments de la bibliothèque standard C peuventêtre utilisés– déclarés dans 18 fichiers commençant par c– déclarés dans 18 fichiers commençant par c
• <cassert>, <cctype>, <cerrno>, <cfloat>, …– au lieu de <assert.h>, <ctype.h>, <errno.h>, <float.h>, …
– les fonctions C appartiennent au namespace global, cellede C++ appartiennent au namespace std
• double sin(double) de math.h appartient au namespaceglobal
• double std::sin(double) de cmath.h appartient aunamespace std
antislashn.orgC vers C++ 203
Bibliothèque standard
• On y trouve toutes les fonctions prévues dans lesversions C++ d'avant la norme de 1998
• Plus un ensemble de patron de classes etfonctions provenant d'une bibliothèque publiquenommée la Standard Template Library (STL)nommée la Standard Template Library (STL)
– développée à l'origine chez Hewlett Packard
antislashn.orgC vers C++ 204
Support du langage
• Fichiers d'en-tête– <cstddef> définit les types dépendant de l'implémentation
• size_t type entier le mieux adapté pour le résultat de sizeof• ptrdiff_t type entier le mieux adapté au résultat de la soustraction de
deux pointeurs
– propriétés de l'implémentation : <limits>, <climits>, <cfloat>– démarrage et terminaison des programmes : <cstdlib>– démarrage et terminaison des programmes : <cstdlib>– gestion dynamique de la mémoire : <new>– identification dynamique des types : <typeinfo>
• pour les dynamic_cast<type>
– gestion des exceptions : <exception>– autres fonctions du runtime :
• <cstdarg> : nombre variables d'arguments• <csetjmp> : "goto" inter fonctions• <ctime> : horloge machine• <csignal> : détection des événements asynchrones
antislashn.orgC vers C++ 205
Chaînes de caractères
• Fichiers d'en-tête
• En C une chaine de caractères est un tableau decaractères dont le dernier élément est le caractèrenull
<string> <cstdlib>
<cstring> <cctype> <cwtype> <cwchar>
caractères dont le dernier élément est le caractèrenull– utilisation de char[] et char *
• En C++ une chaine est un ensemble ordonné decaractères– s'apparente à un vector
– fournit le support pour les caractères ASCII (char) etcaractères étendus (wchar_t)
antislashn.orgC vers C++ 206
Chaînes de caractères
• La classe basic_string utilise un vecteur pourordonner les caractères
– la longueur de la chaîne est variable
– l'accès aux caractères n'est plus aussi directe que pourun tableauun tableau
• des méthodes spécifiques sont ajoutées pour travailler surles intervalles de caractères
• La classe string spécialise basic_string pourles caractères de type char
– améliore grandement l'utilisation par rapport à char *
antislashn.orgC vers C++ 207
Chaînes de caractères
• Constructeurs
– les chaînes se construisent de différentes manières
• à partir d'une chaîne C (char *)
• avec une chaîne littérale
• à partir d'une autre chaîne• à partir d'une autre chaîne
• à partir d'une sous chaîne
• …
antislashn.orgC vers C++ 208
Chaînes de caractères
• Constructeurs
– exemplesint main(int args, char* argv[]){
string s1; // chaine videstring s2 = ""; // chaine videstring s3 = "Hello";
begin() et end()renvoient uneréférence versun caractère, et
antislashn.orgC vers C++ 209
string s3 = "Hello";string s4(s3); // copie s3 dans s4
// copie tous les caractères de s3 dans s5string s5(s3.begin(),s3.end());// copie tous les caractères de s3 dans s5string s6(s3,0,s3.length());
}
un caractère, etnon pas unindice entier
string-1.cpp
Chaînes de caractères
• Accès aux éléments
– par un itérateur et un itérateur inverse
• itérateur string::iterator par begin() et end()
• itérateur inverse string::reverse_iterator parrbegin() et rend()rbegin() et rend()
– par l'operateur index [] surchargé par la classe string
antislashn.orgC vers C++ 210
string s = "Hello world";for(string::iterator it = s.begin() ; it!=s.end() ; it++)
cout << *it;
for(int i=0 ; i<s.length() ; i++)cout << s[i];
string-2.cpp
string-2.cpp
Chaînes de caractères
• Comparaisons
– la méthode compare() retourne le même résultatque le ferait la fonction strcmp()
– les opérateurs == , != , < , <= , > , >= ont étésurchargéssurchargés
antislashn.orgC vers C++ 211
Chaînes de caractères
• Méthodes disponibles sur la classe string pourconvertir vers char * du langage C– data() copie la chaîne de caractères C++ vers un tableau
avant de retourner un pointeur (const char *)• l'instance de string se charge de désallouer le tableau
– ne pas tenter de le faire !!!– ne pas tenter de le faire !!!
• la chaîne ne peut pas être modifiée– le tableau appartient à l'instance de string
– c_str() fonctionne comme data() en ajoutant unnull final
– copy() recopie le contenu de la chaîne dans un bufferfournit par le développeur
• le développeur doit désallouer ce buffer
antislashn.orgC vers C++ 212
Chaînes de caractères
• Ajout de chaîne en fin de chaîne par surcharge del'opérateur +=
– même fonctionnalité que la méthode append()string s = "Hello";s += " world";
string-3.cpp
• Insertion de chaîne par la méthode insert()
• Concaténation par l'opérateur +
antislashn.orgC vers C++ 213
s.insert(6,"!!! ");
s = s + "\tBonjour tout le monde";
string-3.cpp
Chaînes de caractères
• Méthodes de recherche et remplacement
– find() recherche une sous-chaine
– rfind() recherche une sous-chaîne en partant de lafin
– recherche de caractères– find_first_of() recherche de caractères
– find_last_of() recherche de caractères en partantde la fin
– replace() remplace une partie de la chaîne
– erase() supprime un certain nombre de caractères
– substr() extrait une sous-chaîne
antislashn.orgC vers C++ 214
Diagnostics
• Composants signalant les erreurs à l'exécutionregroupés dans les en-têtes
– <stdexcept>
– <cassert>
– <cerrno>– <cerrno>
antislashn.orgC vers C++ 215
Localisation
• Fichier en-tête <locale> utilisé pour lalocalisation
– fonctions sur les caractères de type isxxxx
• isspace, isupper, …
– date et heure– date et heure
– symboles et monétaires
– obtention de chaînes de caractères depuis lecatalogue de messages
antislashn.orgC vers C++ 216
Les outils numériques
• Fichiers d'en-tête concernés
• complex déclare un modèle pour l'utilisation desnombres complexes
<complex> <valarray> <numeric> <cmath> <cstdlib>
nombres complexes
– constructeurs
– comparaisons, opérations arithmétiques
– forme polaire
antislashn.orgC vers C++ 217
Les outils numériques
• valarray et les classes associées permettent lamanipulation des vecteurs (au sensmathématique du terme)
– possibilité de calcul vectoriel comparable aux langagesscientifiquesscientifiques
– manipulation vectorielle des types numériques• bool, char, int, float, double, complex
– chaque opération (binaire ou unaire) sur le typenumérique induit une opération (binaire ou unaire)sur les valarray
antislashn.orgC vers C++ 218
Flux d'entrée - sortie
• Un flux est un contenu lu ou écrit par une partie del'application– plus abstrait qu'un fichier qui est caractérisé par un nom,
un emplacement, droits d'accès, …
– l'information lue ou écrite peut-être de plus ou moinshaut niveau : octet, entier, décimal, chaine, …haut niveau : octet, entier, décimal, chaine, …
• les flux sont organisés en 3 niveaux– le plus abstrait : ios_base
– basic_ios qui intègre la notion de localisation
– basic_iostream qui regroupe les classes destinées àsupporter le formatage des types de base connus par C++
• c'est à ce niveau que nous travaillons
antislashn.orgC vers C++ 219
Flux d'entrée - sortie
• Relations d'héritage entre les flux
ios_base
ios
streambuf
stringbuf filebuf
antislashn.orgC vers C++ 220
istream ostream
istringstream ifstream ostringstream ofstreamiostream
stringstream fstream
Flux d'entrée - sortie
• L'utilisation classique des flux passe par lamanipulation des flux standards
– cout, cin, cerr
• et des classes
– istream et ostream
• Les opérateurs d'insertion << et d'extraction >>sont utilisés pour lire et écrire les types de base
– il est possible d'enrichir les types supportés par lasurcharge des opérateurs à l'aide d'une fonction amie
antislashn.orgC vers C++ 221
Flux – la classe ostream
• L'opérateur << est surchargé pour les différentstypes de baseostream & operator << (expression)
• insertion dans un flux
• reçoit deux opérandes• reçoit deux opérandes– l'instance l'ayant appelé (argument implicite this)
– une expression d'un type de base
• son rôle est de transmettre l'expression au flux en laformatant de façon appropriée
• retourne la référence au flux concerné– permet le chainage
antislashn.orgC vers C++ 222
Flux – la classe ostream
• Il existe dans iostream des fonctions membres– écriture d'un caractère
• ostream &put(char c);
– écriture du contenu d'un buffer• ostream &write(const char *s, int n);• envoie de n caractères• envoie de n caractères• permet l'envoie du caractère null, contrairement à <<
– flush du buffer• ostream &flush();
– positionnement• int tellp();• ostream &seek(int p);• ostream &seek(int o, ios_base::seekdir dir);
antislashn.orgC vers C++ 223
Flux – la classe ostream
• Quelques possibilités de formatage avec <<
– des manipulateurs permettent de formater le flux desortie
int main(void){
int n = 122;
– actions possibles sur le gabarit, précision, choixnotation flottant exponentiel, …
antislashn.orgC vers C++ 224
int n = 122;cout << "par defaut : " << n << endl;cout << "en hexa : " << hex << n << endl;cout << "en decimal : " << dec << n << endl;cout << "en octal : " << oct << n << endl;
}
Flux – la classe istream
• L'opérateur >> est surchargé pour les différentstypes de baseistream & operator >> (type_de_base &)
• extraction depuis un flux
• reçoit deux opérandes– l'instance l'ayant appelé (argument implicite this)
– une lvalue d'un type de base
• son rôle est d'extraire du flux les caractères nécessairespour former une valeur du type de base voulu en réalisantune opération de inverse du formatage opéré parl'opérateur <<
• retourne la référence au flux concerné– permet le chainage
antislashn.orgC vers C++ 225
Flux – la classe istream
• Comme pour ostream, il existe des fonctionsmembres dans iostream qui permettent
– la lecture de caractères ou de séquences de caractères
• fonctions get
– lectures facilitant la lectures de chaine de caractères– lectures facilitant la lectures de chaine de caractères
• fonctions getline, gcount
– fonctions de gestion du buffer
• fonctions tellg, seek, unget, …
antislashn.orgC vers C++ 226
Flux – connexion à un fichier
• Fichier en sortie
– création d'une instance de ofstream
• nécessite l'inclusion de <fstream>
• le constructeur nécessite– le nom du fichier– le nom du fichier
• la manipulation du flux se fait comme pour n'importe quelflux de type ostream
antislashn.orgC vers C++ 227
ofstream outFile("c:\\test.dat");if(outFile.is_open()){
outFile << "Hello " << 10 << endl;outFile.close();
}
Flux – connexion à un fichier
• Fichier en entrée
– création d'une instance de ifstream
• nécessite l'inclusion de <fstream>
• le constructeur nécessite– le nom du fichier– le nom du fichier
• la manipulation du flux se fait comme pour n'importe quelflux de type istream
antislashn.orgC vers C++ 228
ifstream inFile("c:\\test.dat");if(inFile.is_open()){
string s;int n;inFile >> s >> n;cout<< s <<" " <<n << endl;inFile.close();
}
C++11 – smart pointers
• Utilisation du mécanisme de la pile pour libérer lamémoire
– le smart pointer encapsule un pointeur référençant unobjet sur le tas
– lorsque le smart pointer est supprimé de la pile, son– lorsque le smart pointer est supprimé de la pile, sondestructeur est appelé, celui-ci désalloue la mémoireréférencée par la pointeur interne
• Les smart pointers sont implémentés sous formede template
• librairie memory
antislashn.orgC vers C++ 229
C++11 - smart pointer
• Exemple de fonctionnement d'un smart pointertemplate<class T> class SmartPointer{
T *pointeur;SmartPointer(const SmartPointer& a){}void operator=(const SmartPointer& a){}
public:SmartPointer(T* ptr):pointeur(ptr){cout << "++++" << endl;}
antislashn.orgC vers C++ 230
SmartPointer(T* ptr):pointeur(ptr){cout << "++++" << endl;}
~SmartPointer(){cout << "----" << endl;delete pointeur;
}
T& operator*() { return *pointeur; }T* operator->() { return pointeur; }
};
C++11 - smart pointer
• unique_ptr
– ne partage pas son pointeur sous-jacent
– ne peut pas être copié, ni passé à un fonction, niutilisé dans un algorithme de la STL
antislashn.orgC vers C++ 231
source illustration : msdn
C++11 – smart pointer
• shared_ptr
– permet le partage d'un pointeur
– contient un compteur de référence
– le pointeur sous-jacent n'est pas supprimé tant quetous les propriétaires ne sont pas hors de portéetous les propriétaires ne sont pas hors de portée
antislashn.orgC vers C++ 232
source illustration : msdn
C++11 – smart pointer
• weak_ptr
– s'utilise avec shared_ptr
– permet de fournir l'accès au pointeur sous-jacent,sans participer au comptage de référence
antislashn.orgC vers C++ 233
STL – conteneur, itérateur et algorithme
• Les notions de conteneur, itérateur et algorithmesont étroitement liées– interviennent simultanément dans un programme utilisant
les conteneurs
• Conteneur• Conteneur– ensemble de classes permettant de représenter les
structures de données ordonnées• vecteurs, listes, ensembles, tableaux associatifs
– patrons de classes paramétrés par le type de leurséléments
• list <int> li;
• vector <Point> lp;
antislashn.orgC vers C++ 234
STL – conteneur, itérateur et algorithme
• Itérateur– l'itérateur permet de standardiser les actions sur un
conteneur
– permet de parcourir, comparer, manipuler leséléments d'un conteneuréléments d'un conteneur
• sans avoir à ce préoccuper de la structure interne duconteneur
– liste chainée, doublement chainée, liste de tableaux, etc.
• permet au minimum un parcours unidirectionnel– par ++
– différents types d'itérateurs :• unidirectionnel, bidirectionnel, à accès direct
antislashn.orgC vers C++ 235
STL – conteneur, itérateur et algorithme
• Parcours d'un conteneur avec un itérateur
– parcours direct
• les conteneurs fournissent des valeurs particulièresd'itérateur via des méthodes begin() et end()
• ceci permet d'avoir un modèle de parcours standard• ceci permet d'avoir un modèle de parcours standard
antislashn.orgC vers C++ 236
list<int> entiers;list<int>::iterator it;for(it = entiers.begin() ; it != entiers.end() ; it++){
// traitement quelconque sur *it}
STL – conteneur, itérateur et algorithme
• Parcours d'un conteneur avec un itérateur
– parcours inverse
• certains conteneurs fournissent des itérateursbidirectionnels
– on peut appliquer les opérateur ++ et --– on peut appliquer les opérateur ++ et --
• ces conteneurs fournissent– un second itérateur reverse_iterator
– les méthodes
» rbegin() qui pointe sur le dernier élément du conteneur
» rend() qui pointe juste avant le premier élément
antislashn.orgC vers C++ 237
list<int> entiers;list<int>::reverse_iterator rit;for(rit = entiers.rbegin() ; rit != entiers.rend() ; rit++){
// traitement quelconque sur *rit}
STL – conteneur, itérateur et algorithme
• Intervalle d'itérateur
– les conteneurs sont ordonnés
– on peut préciser un intervalle d'itérateur en précisantles bornes sous forme de valeur d'itérateur
• vector<Point>::iterator it1, it2;• vector<Point>::iterator it1, it2;
• si it1 et it2 possèdent des valeurs telles que it2 soitaccessible depuis it1
– c'est-à-dire qu'un certain nombre d'incrémentation it1++ permetd'obtenir la valeur de it2
• alors les valeurs it1 et it2 définissent un intervalle
antislashn.orgC vers C++ 238
STL – conteneur, itérateur et algorithme
• Algorithme
– par le biais des itérateurs beaucoup d'opérationspeuvent être appliquées au conteneur
• quelque soit la nature du conteneur
• quelque soit le type de l'élément• quelque soit le type de l'élément
– par exemple : trouver le premier élément ayant unevaleur donnée
• il faut que l'égalité entre les éléments soit convenablementdéfinie
– surcharge de l'opérateur ==
antislashn.orgC vers C++ 239
STL – conteneur, itérateur et algorithme
• Algorithme
– les différents algorithmes sont fournis sous forme depatron de fonctions
• paramétrés par le type des itérateurs
• exemple : comptage du nombre d'élément valant 1• exemple : comptage du nombre d'élément valant 1
– ce même modèle de code est réutilisable sur une liste, sur destypes différents
antislashn.orgC vers C++ 240
vector<int> entiers;int nb = count(entiers.begin(),entiers.end(),1);
STL – conteneur, itérateur et algorithme
• Les conteneurs se différencient entre eux parleurs caractéristiques– celles-ci doivent être indépendantes de
l'implémentation
– se différencient aussi par l'efficacité de certaines– se différencient aussi par l'efficacité de certainesopérations
• La norme classe les conteneurs en– conteneurs en séquences (conteneurs séquentiels)
– conteneurs associatifs
• les éléments d'un conteneur sont ordonnés
antislashn.orgC vers C++ 241
STL – Conteneurs
• Construction d'un conteneur– la construction d'un conteneur d'objets non vide dont les
éléments sont des objets entraine, pour chaque élément• soit l'appel d'un constructeur
– construction d'un vecteur de 3 points
• soit l'appel d'un constructeur par recopie
vector<Point> v(3);
vector<Point> w(v);• soit l'appel d'un constructeur par recopie– construction d'un vecteur à partir d'un autre
» appel du constructeur par recopie de vector<Point> qui appelle leconstructeur par recopie de Point
– une construction par affectation• peut appeler l'opérateur d'affectation si la taille de w est
suffisante
• ou destruction de w et recopie de v si la taille de w estinsuffisante
antislashn.orgC vers C++ 242
vector<Point> w(v);
w = v;
STL – Conteneurs
• Attention, le passage d'un conteneur en tantqu'argument de fonction est effectué par valeur
– il y a donc recopie de tous les éléments du conteneur
– préférez le passage par référence
Certaines opérations sur les conteneurs peuvent• Certaines opérations sur les conteneurs peuventaussi appeler des méthodes de la classe élément
– recherche, comparaison, …
antislashn.orgC vers C++ 243
STL – algorithmes : fonctions, prédicats etclasses fonctions• Fonction unaire
– permet d'appliquer une fonction aux différentséléments d'une séquence
• la séquence correspond à un intervalle d'itérateurs
• cette fonction est alors passée en argument de l'algorithmecette fonction est alors passée en argument de l'algorithme
– f doit posséder un argument du type des éléments
– l'éventuelle valeur de retour n'est pas utilisée
• Prédicat– fonction qui retourne une valeur de type bool
– utilisée par certains algorithmes comme find_if
antislashn.orgC vers C++ 244
for_each(it1, it2, f);
find_if(it1,it2, f);
STL – algorithmes : fonctions, prédicats etclasses fonctions• Certains algorithmes ou fonctions membres
nécessitent un prédicat comme argument– fonction callback
• Cette fonction est en général prévue dans ladéfinition du patron, sous forme d'un objet de typedéfinition du patron, sous forme d'un objet de typequelconque
• Classes fonctions prédéfinies dans <functional>– par exemple less(int) instancie une fonction patron
correspondant à la comparaison par < de deux int• patrons existants pour les opérateurs
– equal_to pour ==, not_equal_to pour !=, greater pour >, lesspour <, greater_equal pour >= et less_equal pour <=
antislashn.orgC vers C++ 245
STL – relation d'ordre
• Il est parfois nécessaire de connaitre une relation permettantd'ordonner les éléments d'un conteneur– pour des questions d'efficacité les éléments d'un conteneur
associatif sont ordonnés– tri sur certains conteneur
• Il faut redéfinir l'opérateur < qui est utilisé comme relationnaturellenaturelle
• Générateur d'opérateur– on peut théoriquement redéfinir les opérateurs == et !=
• de même pour <, <=, >, >=
– la STL dispose de patrons de fonctions permettant de définir• l'opérateur != à partir de ==• les opérateurs >, >= et <= à partir de <
– il suffit donc de munir une classe des opérateurs == et < pour qu'elledispose des autres
antislashn.orgC vers C++ 246
STL – Conteneurs séquentiels
• Conteneurs séquentiels– vector
• généralise la notion de tableau• iterateur à accès direct
– list• liste doublement chainéesliste doublement chainées• itérateur bidirectionnel
– deque• classe intermédiaire
• Adaptateurs de conteneur– stack– queue– priority_queue
antislashn.orgC vers C++ 247
STL – Conteneurs séquentiels
• Fonctionnalités communes
– construction
• conteneur vide
• avec un nombre d'éléments donné
vector<Point> v;
vector<Point> v(3);
• avec un nombre donné d'éléments initialisés
• à partir d'une séquence
• à partir d'un autre conteneur du même type
antislashn.orgC vers C++ 248
vector<Point> v(3);
Point p(1,2);list<Point> lp(10,p);
list<Point>lpi(lp.begin(),lp.end());
list<Point> lpi2(lpi);
STL – Conteneurs séquentiels
• Fonctionnalités communes
– modifications globales
• affectation
• méthode assign
vector<Point> v1(…) v2(…);v1 = v2;
• méthode assign
– permet de travailler entre conteneurs de types différents
• méthode clear : vide le conteneur
• méthode swap : échange le contenu de deux conteneurs
antislashn.orgC vers C++ 249
vector<Point> v1(…);list<Point> l1(…);Point p(…);l1.assign(10,p);l1.assign(v1.begin(),v1.end());
types de conteneurdifférents
10 élements avec valeur p
STL – Conteneurs séquentiels
• Fonctionnalités communes– comparaison de conteneur
• opérateur ==– si c1 et c2 sont deux conteneurs du même type c1 == c2 sera
vrai s'ils sont de même taille et si les éléments de même rang sontégauxégaux
• opérateur <– effectue une comparaison lexicographique des deux conteneurs
– compare les éléments du même rang avec l'opérateur < ets'interrompt si
» la fin d'un des conteneur est atteinte
» la comparaison entre deux éléments est fausse
• les opérateurs !=, <=, > et >= sont également disponibles
antislashn.orgC vers C++ 250
STL – Conteneurs séquentiels
• Fonctionnalités communes
– insertion d'éléments• insert(position, valeur)
• insert(position, nb_fois, valeur)
• insert(debut_intervalle,fin_intervalle,position)
– suppression d'éléments• erase(position)
• erase(debut_intervalle,fin_intervalle)
antislashn.orgC vers C++ 251
STL - vector
• Reprends la notion de tableau
– accès direct avec la même efficacité quelque soit lenombre d'éléments
– la taille peut varier en cours d'exécution
• Accès aux éléments• Accès aux éléments
– par itérateur
– par indice, via l'opérateur []
– accès au dernier élément, méthode back()
antislashn.orgC vers C++ 252
vector<int> v(10);v.back() = 33;
STL - vector
• Insertions et suppressions
– efficacité réduite avec erase et insert
• en C(n) pour les vecteurs, en C(1) pour les listes
– efficacité en C(1) en fin• insertion en fin, méthode push_back(valeur)• insertion en fin, méthode push_back(valeur)
• suppression en fin, méthode pop_back()
antislashn.orgC vers C++ 253
STL - vector
• Gestion mémoire– la norme n'impose pas d'implémentation– elle impose des contraintes d'efficacité– certaines opérations sur les vecteurs entrainent l'invalidation
des itérateurs ou références sur des éléments• augmentation de taille• insertion d'un élément• insertion d'un élément• certaines suppressions d'éléments
– méthodes outils :• size() : nombre d'éléments• capacity() : taille potentielle d'un vecteur• reserve(taille) : impose une taille minimale• max_size() : taille maximale allouable au vecteur• resize(taille) : modifie la taille
antislashn.orgC vers C++ 254
STL - deque
• Offre des fonctionnalités voisine de vector– accès direct aux éléments avec un complexité C(1)
• Ajoute une insertion et suppression au début– également en C(1)
• Une opération sur un deque sont moins rapide que lamême opération sur un vectormême opération sur un vector
• On ne dispose pas de capacity() et reserve()• Accès au premier élément par front()• Suppression du premier élément par pop_front()• Insertion d'un premier élément parpush_front(valeur)
antislashn.orgC vers C++ 255
STL - list
• Concept de liste doublement chainée
– itérateur bidirectionnel
– insertions et suppressions efficaces quelle que soit laposition
– pas d'itérateur à accès direct– pas d'itérateur à accès direct
• les itérateurs peut être manipulés avec ++ et --, mais pas depossibilité d'incrémentation avec une valeur quelconque
• obligation de parcourir la liste depuis le début
– list dispose de front() et back(), comme pour laclasse deque
antislashn.orgC vers C++ 256
STL - list
• Insertions et suppressions
– les fonctionnalités générales possèdent unecomplexité C(1)
– possibilité d'utiliser push_front(valeur),push_end(valeur), pop_front() et pop_end()push_end(valeur), pop_front() et pop_end()
– suppression de tous les éléments d'une valeur donnéepar remove(valeur)
– suppression par prédicat par remove_if(predicat)
antislashn.orgC vers C++ 257
int t[] = {1,2,1,3,1,4,1,5};list<int> li(t,t+8);li.remove(1);
bool isPaire(int i) {return !(i%2);…li.remove_if(isPaire);
STL - list
• Opérations globales : en plus des fonctionscommunes
– tri par sort()
– suppression des doublons par unique()
fusion de deux listes par– fusion de deux listes par merge()
– transfert entre une partie d'une liste dans une autrepar splice(debut_sequence,fin_sequence)
• Gestion mémoire
– on ne retrouve aucune fonction permettant d'agir surles allocations, comme capacity et reserve
antislashn.orgC vers C++ 258
STL – les adaptateurs de conteneur
• Trois patrons queue, stack et priority_queue
• Classes construites sur un conteneur pourl'adapter à des fonctionnalités spécifiques
– disposent toutes d'un constructeur par défaut
• Patrontype_adaptateur <type_element, type_conteneur>
antislashn.orgC vers C++ 259
STL - stack
• Gestion des piles LIFO– construction sur vector, list ou deque
– méthodes
stack<int, vector<int> > s1;stack<int, deque<int> > s2;stack<int, list<int> > s3;
– méthodes• empty() : true si la pile est vide
• size() : nombre d'éléments dans la pile
• top() : accès à la donnée au sommet – consultation oumodification
• push(valeur) : ajout d'un élément sur la pile
• pop() : supprime la valeur au sommet de la pile
antislashn.orgC vers C++ 260
STL - queue
• Gestion de file d'attente FIFO– construction sur list ou deque
• vector n'est pas approprié car pas d'accès en début
– méthodes
queue<int, deque<int> > q1;queue<int, list<int> > q2;
– méthodes• empty() : true si la pile est vide• size() : nombre d'éléments dans la liste• front() : accès à la donnée en tête – consultation ou
modification• back() : fournit la valeur de l'élément en fin – consultation ou
modification• push(valeur) : ajout d'un élément dans la file• pop() : fournit la valeur de l'élément en tête, en le supprimant
antislashn.orgC vers C++ 261
STL – priority_queue
• Gestion de file d'attente FIFO– ajout des éléments toujours en fin, avec une certaine
priorité définie par une relation d'ordre défini sous formed'un prédicat
– construction uniquement sur deque
priority_queue<int, deque<int> > q1;
– méthodes• empty() : true si la pile est vide• size() : nombre d'éléments dans la liste• top() : accès à la donnée en tête – consultation ou modification• push(valeur) : ajout d'un élément dans la file• pop() : fournit la valeur de l'élément en tête, en le supprimant
antislashn.orgC vers C++ 262
priority_queue<int, deque<int> > q1;priority_queue<int, deque<int>, greater<int> > q2;
STL – conteneurs associatifs
• Permet de retrouver une information par une clé et nonplus par sa position– l'élément est formé d'une clé et d'une valeur
• map impose l'unicité de la clé, multimap ne l'impose pas– l'opérateur [] sera permis sur le map, pas sur le multimap
• Deux autres conteneurs correspondent à des cas• Deux autres conteneurs correspondent à des casparticuliers de map et multimap– dans le cas ou la valeur associée à la clé n'existe pas
• les éléments se limitent à une seule clé
– set et multiset permettent de représenter des ensembles ausens mathématique
• présence d'une relation d'ordre appropriée
• le multiset permet la présence de plusieurs éléments identiques
antislashn.orgC vers C++ 263
STL - pair
• Patron de classe pair– permet de regrouper dans un objet deux valeurs
• Construction– à deux arguments
– affectation
pair <int, float> p (2, 1.3);
– affectation
– fonction make_pair
– membres publiques first et second
• La classe pair dispose des opérateurs == et <
antislashn.orgC vers C++ 264
p = pair<int, float>(8,6.3);
p = make_pair(7, 6.3f);
p.first=7; p.second=6.3;
STL - map
• Les éléments d'un map sont formés de deuxparties
– une clé et une valeur
• Permet d'accéder rapidement à la valeur associéeà la cléà la clé
– par l'opérateur []
– complexité en C(Log n)
• Patron de classe pair
– permet de regrouper dans un objet deux valeur
antislashn.orgC vers C++ 265
STL - map
• Construction d'un map
– par utilisation de la relation d'ordre par défaut (<)
• construction d'un conteneur vide
• construction par recopie d'un conteneur de même type
map<char, Point> m1;
• construction par recopie d'un conteneur de même type
• construction à partir d'une séquence
antislashn.orgC vers C++ 266
map<char, Point> m2(m1);
list< pair<char, Point> > lr(…);map<char, Point> m (lr.begin(),lr.end());
STL - map
• Construction d'un map
– choix de l'ordre
• on impose au conteneur une relation autre que l'ordrenaturel sous forme d'un prédicat binaire prédéfini (commeless ou greater)less ou greater)
• la fonction membre key_comp() fournit la fonction utiliséepour ordonner les clés
antislashn.orgC vers C++ 267
map<char, Point, greater<char> > m1;
STL - map
• Accès aux éléments– par l'opérateur []
• si une clé n'existe pas, elle est créée
map<char, int> m;m['S'] = 3;… = m['a'];
la paire ('S',3) est créée si la clén'existe pas, sinon la valeur de l'élémentest modifié
– accès par itérateur• on peut accéder aux éléments de la paire par les propriétés
publiques first et second
– recherche par la méthode find(clé) qui fournit unitérateur sur l'élément ayant une clé donnée
antislashn.orgC vers C++ 268
… = m['a'];
si la clé 'a' n'existe pas, création d'unepaire ('a',0)
(*it).first;
STL - map
• Insertions
– la méthode insert permet
• l'insertion d'une valeur donnée– insert(paire)
• les éléments d'un intervalle• les éléments d'un intervalle– insert(debut_sequence,fin_sequence)
• à une position donnée– insert(position,paire)
» la position est une suggestion faite pour facilité la recherche
antislashn.orgC vers C++ 269
STL - map
• Suppressions– la méthode erase permet
• la suppression à une position donnée– erase(position)
• les éléments d'un intervalle– erase(debut_sequence,fin_sequence)– erase(debut_sequence,fin_sequence)
• l'élément d'une clé donnée– erase(clé)
– la méthode clear() vide le conteneur
• Gestion mémoire– les opérations sur les map n'entrainent jamais
d'invalidation des références et des itérateurs
antislashn.orgC vers C++ 270
STL - multimap
• Une même clé peut apparaitre plusieurs fois– pas d'opérateur []– find(clé) fournit un itérateur sur un des éléments ayant la clé
recherchée• pas nécessairement le premier, il faut utiliser la fonction lower_bound
– erase(clé) supprime plusieurs éléments– permet de connaitre le nombre d'élément ayant– count(clé) permet de connaitre le nombre d'élément ayant
une clé donnée– informations sur l'intervalle d'éléments ayant une clé
équivalente• lower_bound(clé) : itérateur sur le 1er élément• upper_bound(clé) : itérateur sur le dernier élément• equal_range(clé) : fournit une paire des valeurs constituée des
deux itérateurs précédents
antislashn.orgC vers C++ 271
STL – set multiset
• set est un cas particulier du map
– aucune valeur n'est associée à la clé
– un élément d'un set est une constante, on ne peutpas le modifier
• est un autorisant plusieurs clés• multiset est un set autorisant plusieurs cléséquivalentes
antislashn.orgC vers C++ 272
STL – algorithmes standards
• Les algorithmes standards se présentent sous laforme de patrons de fonction
– le code n'a pas la connaissance précise des élémentsqu'il devra manipuler
• la manipulation des éléments passent par les itérateurs• la manipulation des éléments passent par les itérateurs
antislashn.orgC vers C++ 273
STL – algorithmes standards
• Les différentes catégories d'itérateur– nous avons rencontrés les itérateurs unidirectionnels,
bidirectionnels et à accès direct– il existe deux autres types d'itérateurs
• en entrée• en sortie• en sortie
– on peut hiérarchiser les itérateurs
antislashn.orgC vers C++ 274
itérateur en entrée itérateur en sortie
itérateur unidirectionnel
itérateur bidirectionnel
itérateur à accès direct
STL – algorithmes standards
• itérateur en entrée (in)– opérations possibles
• affectation : it1 = it2
• incrémentation : it++ ou ++it
• lecture : a = *it– impossible de faire *it = a
– impossible de faire– impossible de faire a = *it; b = *it;
• test d'égalité : it1 == it2
– comme un itérateur unidirectionnel, mais ne permet pasde modifier la valeur correspondante
– n'autorise qu'un seul passage sur les éléments de lacollection
• type d'itérateur utilisé pour la lecture de flux– il n'est pas possible de lire deux fois une même valeur sur certains flux,
comme l'entrée standard
antislashn.orgC vers C++ 275
STL – algorithmes standards
• itérateur en sortie (out)– opérations possibles
• affectation : it1 = it2
• incrémentation : it++ ou ++it
• écriture : *it = a– impossible de faire a = *it– impossible de faire *it = a; *it = b;– impossible de faire *it = a; *it = b;
– comme un itérateur unidirectionnel, mais ne permet pasde modifier la valeur correspondante
– n'autorise qu'un seul passage sur les éléments de lacollection
• type d'itérateur utilisé pour l'écriture sur un flux– il n'est pas possible d'écrire deux fois une même valeur au même
endroit, comme sur la sortie standard
antislashn.orgC vers C++ 276
STL – algorithmes standards
• Itérateur unidirectionnel (for pour forward)– permet de balayer du début à la fin
• sans retour en arrière
– les opérations sur les itérateurs in et out sont disponibles surcet itérateur
• partout où un itérateur in ou out est requis, peut être remplacé par unitérateur foritérateur for
• Itérateur bidirectionnel (bi)– comme for avec en plus it-- et --it
• Itérateur à accès direct (ran)– comme bi avec en plus
• opérateur [] : it[3];• arithmétique sur les itérateurs : it+=3;• offre les mêmes fonctionnalités qu'un pointeur conventionnel
antislashn.orgC vers C++ 277
STL – algorithmes standards
• Algorithmes et séquences
– de nombreux algorithmes s'appliquent sur uneséquence définie par un intervalle d'itérateurs
• les arguments sont classiquement les début et fin deséquenceséquence
– certains algos s'appliquent à deux séquences demême taille
• recopie par exemple
• les arguments à passer sont alors– deux arguments de début et fin pour la première séquence
– un troisième argument pour le début de la seconde séquence
antislashn.orgC vers C++ 278
STL – algorithmes standards
• Itérateur d'insertion– de nombreux algos doivent modifier les valeurs d'une
séquence
– patron de classe insert_iterator
insert_iterator <list<int> > ins;
• pour affecter une valeur à cet itérateur on utilise le patron defonction inserter
– c est le conteneur
– it est l'itérateur où se fera l'insertion
– il existe trois fonctions pour la valeur initiale de l'insertion» inserter(conteneur, position)
» front_inserter(conteneur)
» back_inserter(conteneur)
antislashn.orgC vers C++ 279
ins = inserter(c, it);
STL – algorithmes standards
• Itérateurs de flux
– itérateur de flux de sortie
• patron ostream_iterator
• exemple sur la sortie standardostream_iterator<char> flcar(cout);
– itérateur de flux d'entrée
• patron istream_iterator
• exemple sur l'entrée standard
antislashn.orgC vers C++ 280
ostream_iterator<char> flcar(cout);*flcar = 'a';
istream_iterator<int> flint(cin);int i = *flint;
STL – algorithmes standards
• Algorithmes d'initialisation d'intervalles
– copie d'une séquence• copy(debut_sequence,fin_sequence,iterateur);
– copie à partir de debut_sequence vers iterateur
– les éléments doivent être de même typeles éléments doivent être de même type
• copie inverse avec copy_backward
– génération de valeurs• generate(debut_sequence,fin_sequence,fonction);
– ou la fonction fonction génère les valeurs
• voir aussi generate_n, et fill
antislashn.orgC vers C++ 281
STL – algorithmes standards
• Algorithmes de recherche– recherche de valeur
• la valeur est imposée
• les algos sont basés sur l'égalité ==, ou un prédicat unairefournit sous forme de fonction
: recherche une valeur– find : recherche une valeur
– find_first : recherche une valeur parmi plusieurs
– search_n : recherche une valeur répétée n fois
– adjacent_find : recherche les doublons adjacents
– recherche d'extremum• max_element et min_element
– utilisent <, ou une relation donnée sous forme de prédicat binaire
antislashn.orgC vers C++ 282
STL – algorithmes standards
• Algorithmes de transformation
– remplacements de valeurs• replace(debut_seq,fin_seq,old_val,new_val);
– remplace toutes les old_val par new_val dans la séquence
• replace_if(debut_seq,fin_seq,condition,new_val);
– remplace toutes valeurs satisfaisant à une condition
• famille des fonctions en xxx_copy qui réalise le mêmetraitement que xxx sans modifier la séquence d'origine eten copiant dans une autre séquence
– replace_copy, reverse_copy
antislashn.orgC vers C++ 283
STL – algorithmes standards
• Algorithmes de transformation
– permutations de valeurs
• rotate : permutation circulaire d'une séquence
• génération de permutation en changeant l'ordre de la listeordonnéeordonnée
– next_permutation et prev_permutation
• random_shuffle : permutation aléatoire des valeurs de laséquence
antislashn.orgC vers C++ 284
STL – algorithmes standards
• Algorithmes de suppression
– remove(debut, fin, val) : supprime tous leséléments d'une valeur val donnée
• utilise l'opérateur ==
• voir aussi remove_if qui se base sur un prédicat unaire• voir aussi remove_if qui se base sur un prédicat unaire
– unique(debut,fin) : ne conserve que la premièrevaleur d'une série de valeurs égales
– renvoie un itérateur sur la fin du remaniement de lacollection
antislashn.orgC vers C++ 285
STL – algorithmes standards
• Algorithmes de tri
– la plupart de ces algorithmes nécessites des itérateursà accès direct
– le tri est effectué par l'opérateur < ou par un prédicatbinairebinaire
– on peut réaliser des tris complets, ou sur uneséquence particulière
• sort, partial_sort
antislashn.orgC vers C++ 286
STL – algorithmes standards
• Algorithmes de recherche et fusion
– s'appliquent sur des séquences ordonnées
– algos de recherche dichotomique (binaire)• binary_search
– lower_bound et upper_bound fournissent les première et– lower_bound et upper_bound fournissent les première etdernière positions possibles
– algos de fusion
• fusionne deux séquences ordonnées pour les réunir dansune troisième
– merge fusionne deux séquences en une troisième
– implace_merge fusionne deux séquences en une seul
antislashn.orgC vers C++ 287
STL – algorithmes standards
• Algorithmes à caractère numérique
– algos qui effectuent des opérations fondées sur lesopérateurs numériques : +, - , *
• accumulate : somme des éléments d'une séquence
• inner_product : produit scalaire de deux séquences de• inner_product : produit scalaire de deux séquences demême taille
• partial_sum : crée une nouvelle séquence formée descumuls partiels d'une première séquence
• adjacent_difference : crée une séquence formée de ladifférence de deux éléments consécutifs
antislashn.orgC vers C++ 288
STL – algorithmes standards
• Algorithmes à caractère ensembliste– permet de faire des unions, intersection, différences
sur les ensembles• se fondent sur l'opérateur == ou un prédicat binaire
– set_union, set_intersection, set_difference
• Algorithmes de manipulation de tas• Algorithmes de manipulation de tas– algos bas niveaux
– la notion de tas est fondée sur celle d'arbre binaire• make_heap permet de réarranger une séquence sous forme
de tas
• pop_heap, push_heap, sort_heap permettent lamanipulation du tas
antislashn.orgC vers C++ 289
C++11 - tuple
• Collection de taille fixe d'objets de typesdifférents
– include <tuple>
• Fonctions membres
– constructeur, operator=, swap
• Fonctions tiers
– make_tuple, get, opérateurs de comparaison, …
antislashn.orgC vers C++ 290
Google Protocol Buffers
• Protocol Buffers (noté PB) permet la sauvegarde dedonnées structurées sous forme textuelle et binaire– texte : lisible
– binaire : compacte et simple à traiter en programmation
– c'est une alternative à XML– c'est une alternative à XML
• PB est multi-langage, multiplateforme– mis au point par Google pour ses propres besoins
– spécification d'un protocole de sérialisation
– porté en C++, Java et Python
– site de référence :http://code.google.com/intl/fr/apis/protocolbuffers/docs/overview.html
antislashn.orgC vers C++ 291
Google Protocol Buffers
• Une donnée structurée est simple à traiter si elleest sous forme d'objet en mémoire, et persistéedans un fichier.
– principe de la sérialisation sur fichier
• Google fournit un compilateur qui à partir d'un• Google fournit un compilateur qui à partir d'undocument (le proto) génère la classe.
– cette classe comporte les méthode de sérialisation etdésérialisation vers le fichier
antislashn.orgC vers C++ 292
Google Protocol Buffers
• Étapes de développement
1. définition de la structure proto
2. compilation par le compilateur de la classe
• cette classe est dérivée d'une classe Message
3. écriture de l'application qui utilise la classe générée3. écriture de l'application qui utilise la classe générée
4. compilation habituelle
• lien avec la librairie protobuf
5. l'état de l'instance peut être sérialisé dans un fichier.proto
antislashn.orgC vers C++ 293
Google Protocol Buffers
• Téléchargement des archives– http://code.google.com/p/protobuf/downloads/list
– deux archives• compilateur• librairies
• Récupérer le projet VSProjects et lancer la compilationen mode Release– en mode Release
• Lancer les tests– exécutables qui ont étés créés lors de la compilation du projet
• Lancer l'utilitaire extract_includes.bat• Copier les fichiers *.lib générés• le fichier readme.txt livré avec le projet explique le
déroulement de la compilation
antislashn.orgC vers C++ 294
Google Protocol Buffers
• Création d'un fichier proto minimaliste
– fichier Hello.protomessage Hello{required string data =1 [default="Hello, world"];}
– le champ data de type string est obligatoire
• peut-être required ou optional
– le numéro d'ordre (=1) du champ
– la valeur par défaut
• optionnel
antislashn.orgC vers C++ 295
Google Protocol Buffers
• Compilation du fichier Hello.proto
• Ce qui génère les fichiers
protoc --cpp_out=. Hello.proto
espacedeux tirets
• Ce qui génère les fichiers
– Hello.pb.cc et Hello.pb.h
– Dans le fichier .h apparait les méthodes pour notrepropriété data
• has_data(), clear_data(),set_data(…), data()
• Faire un nouveau projet pour tester la classe
antislashn.orgC vers C++ 296
Google Protocol Buffers
• Présentation de l'API
– Méthodes héritées de Message
• IsInitialized() : vérifie si tous les champs sont initialisés
• DebugString() : renvoie le message sous forme de string
• CopyFrom(…) : met à jour le Message• CopyFrom(…) : met à jour le Message
– Sérialisation
• SerializeToString(…) : sérialise sous forme de chaine
• SerializeToOstream(…) : sérialisation binaire
• ParseFromString(…) : désérialise depuis une chaine
• ParseFromIstream(…) : désérialisation binaire
antislashn.orgC vers C++ 297
Bibliographie
• Le langage et la bibliothèque C++ - Norme ISO
– Henri Garreta - Ellipses
• Passeport pour C++ - Concepts et mise enpratique
– Georges Hansel – Vuibert
• Effective C++ - 55 Specific ways to improve yourprograms
– Scott Meyers
antislashn.orgC vers C++ 298
Web
• site de Bjarne Stroustrup• http://www2.research.att.com/~bs/homepage.html
• C++ Faq-lite• http://jlecomte.ifrance.com/c++/c++-faq-lite/index-fr.html
• Code de grande personne• http://h-deb.clg.qc.ca/Sujets/
• Google :• Google :– Google C++ Style Guide
• http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Nested_Classes
– Sérialisation• http://code.google.com/intl/fr/apis/protocolbuffers/docs/overview.html
• Qt– Designing Qt-Qtyle C++ APIs
• http://doc.trolltech.com/qq/qq13-apis.html
antislashn.orgC vers C++ 299
Copyleft
Support de formation créé par
Franck SIMON
http://www.franck-simon.com
antislashn.orgC vers C++ 300
Copyleft
Cette œuvre est mise à disposition sous licence Attribution
Pas d'Utilisation Commerciale
Partage dans les Mêmes Conditions 3.0 France.
Pour voir une copie de cette licence, visitezhttp://creativecommons.org/licenses/by-nc-sa/3.0/fr/http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
ou écrivez à
Creative Commons, 444 Castro Street, Suite 900, Mountain
View, California, 94041, USA.
antislashn.orgC vers C++ 301