Langage algorithmique (LA) Plan du coursJean-Marc.Pierson/coursC++.pdfDépartement Informatique de...
Transcript of Langage algorithmique (LA) Plan du coursJean-Marc.Pierson/coursC++.pdfDépartement Informatique de...
Programmation objet en langage C++ 1Département Informatique de l'INSA- Jean-Marc Pierson
Langage C++ - Jean-Marc Pierson -INSA Lyon
Plan du cours
• Langage algorithmique
• Notion de qualité des algorithmes
• Le langage C++
Langage algorithmique (LA)
Pourquoi faire ?
• s'accorder sur une manière de décrire un algorithme
• s'abstraire des contraintes pures de codage (oubli de point-virgule, …)
• se concentrer sur le fonds plutôt que sur la forme
LA : comment faire ?
• être rigoureux dans ses descriptions• lever toutes les ambiguïtés• décrire un algorithme dans une forme telle
que la passage au codage ne pose plus aucun problème, pour que cette opération de codage devienne une simple mécanique de traduction du LA vers le langage cible
LA : comment faire (suite)• Techniquement :
– Indenter pour séparer les divers blocs– Bien repérer le début et la fin des instructions
• Ne pas hésiter à mettre des commentaires : en début de méthode ou de fonction expliquant son fonctionnement général, ou dans l'algorithme lorsque c'est nécessaire à la compréhension de l'algorithme
(pas du style : i := i + 1 // commentaire : on incrémente la variable i !)
Programmation objet en langage C++ 2Département Informatique de l'INSA- Jean-Marc Pierson
LA : quelques exemples
si expression alorsinstruction1
sinoninstruction2instruction3
fin_si
tantque expression faireinstruction1instruction2
fin_tantque
nom_var := expression
entier nombreLu
caractère caractereLu
Déclaration
Affectation
Test
Tant quePourpour expression faire
instruction1instruction2
fin_pour
Exemple : factoriellefonction factorielle (entier n:0..+inf) renvoie entier
entier fdebut
f := 1 tant que (n <> 1) faire
f := f * n n := n – 1
fin_tantqueretourne f
fin
Évaluation de la complexité
• Complexité temporelle : temps d'exécution ;nombre d'instructions élémentaires à faire dans l'algorithme à évaluer (question : qu'est-ce qu'une instruction élémentaire ?);
• Complexité spatiale : place occupée par les données;
• dépendent de la représentation des données (type abstrait utilisé) et du nombre d'éléments stockés
Complexité temporelle• on note O(f(n)) la complexité d'un algorithme, où n est
le nombre d'éléments à traiter par l'algorithme; ceci signifie que la complexité peut-être estimée par c.f(n)où c est une constante;
• on s'intéresse à son comportement asymptotique lorsque n est grand
• quelques exemples : – O(1) : indépendant de n ; ex : récupération d’un élément d'un
tableau – O(n) : parcours d'un tableau de n éléments– O(n3) : multiplication de deux matrices n*n
Programmation objet en langage C++ 3Département Informatique de l'INSA- Jean-Marc Pierson
Produit de matriceb11 b12 b13 ………. b1n
b21 b22 ………...…b2n
..
....... bnn
a11 a12 a13....... a1n x11 x12 …..a21 a22 ….…… a2n ….… ….…… ann xnn
x11 = a11*b11 + a12*b21+… + bn1*a1n
n multiplications et n-1 additions = 2n-1 op.
n2*(2n-1)
O(n3)
Complexité et vitesse d’exécutionMesure de la vitesse : pour une vitesse d'exécution de 1
teraflops (=1000 gigaflops = 106 megaflops = 109
flops = 1 milliard d’opérations en « virgule flottante » par seconde), une complexité en O(n3), avec n=100000=105 donne 1015 instructions élémentaires et donc 106 secondes, soit plus de 11 jours et demi !
• le plus puissant aujourd’hui : 35 Teraflopshttp://www.top500.org/
Complexité spatiale
• On peut aussi la présenter sous la forme O(f(n))
• mais on préfère la présenter sous la forme de nombre d'octets (à cause de la constante c qui rend trop imprécise l'estimation : pour n=100000 éléments, O(n) peut aussi bien exprimer 400000 que 1200000 octets !)
"Programmation objet en C++"• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques• héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++ / Les entrées sorties
Programmation objet en langage C++ 4Département Informatique de l'INSA- Jean-Marc Pierson
Plan "Programmation objet en C++"
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
La programmation orientée objet • Un programme exécutable = ensemble d'OBJETS
communiquant par envoi de messages . • Tout objet est une instance d'une CLASSE, dans laquelle
sont définis– les informations encapsulées (attributs)– les algorithmes des traitements de messages(méthodes) .
• Programme source = ensemble de définitions de classes (et de fonctions)
• Une classe peut être une spécialisation d'une autre classe : "héritage"
Intérêts de l'approche objet
• Tous ceux de l'approche "types abstraits"- Modularité- Séparation spécification/réalisation- Encapsulation
• + Réutilisabilité- Spécialisation via l'héritage- Constitution de bibliothèques de classes
• + Évolutivité- grâce à l'héritage
Terminologie LOO• classe concrète : une classe dont toutes les méthodes
sont réalisées• classe abstraite : une classe dont au moins une
méthode n'est pas réalisée• classe générique : une classe "paramétrable" : par
exemple, une Pile peut être générique et être utilisée soit comme une pile d'entier, soit comme une pile de réels
Programmation objet en langage C++ 5Département Informatique de l'INSA- Jean-Marc Pierson
Terminologie LOO (suite)
• Sous-classe (dérivée, descendant, spécialisation)
relation "Est-Un" ("sorte de") par exemple :
un Salarié est une sorte de Personneun Cercle est une sorte de FormeGeometrique
• Super-classe (ancêtre)
Terminologie LOO (fin)
• Objet = "Instance d'une classe"par exemple, Paul est une Personne (Paul est une instance de la classe Personne)
• Attribut = variable d'instancepar exemple, un attribut de Paul est son Nom; un autre attribut pourrait être son Adresse
• Méthode d'instance = réaction d'un objet à la réception d'un message
• variable de classe, méthode de classe : non reliées à une instance, propre à la classe
Principales caractéristiques du C++• Langage puissant• Construit sur le langage C:
– un meilleur C– programmation par types abstraits– programmation objet
• Réutilisation des bibliothèques C• Manipulation mixte d'objets et de variables de types
primitifs C• Moins pur que d'autres LOO (Smalltalk, Java)• Nombreux environnements de développement
Principales caractéristiques du C++ (suite)
• Surcharge de fonctions• Surcharge d'opérateurs• Généricité des classes et fonctions• Librairies standards de classes et fonctions • Héritage multiple
Programmation objet en langage C++ 6Département Informatique de l'INSA- Jean-Marc Pierson
C++ et les autres langages
Simula 67
Ada 95
Ada
C
Smalltalk
70
80
90
96
Pascal
C++Eiffel
Java
Langages objet
Références Web• Site Web :
– http://www.cplusplus.com– http://casteyde.christian.free.fr/cpp/– http://www.icce.rug.nl/docs/cplusplus/cplusplus.html– http://www.BruceEckel.com– http://www.examware.com/tutor6.html– http://devcentral.iftech.com/learning/tutorials/c-
cpp/cpp/– http://perso.club-internet.fr/pprados/Langage/CPP/
Bibliographie• Bjarne Stroustrup. "Le langage C++". 2ème édition. Addison-
Wesley, 1992• Margaret Ellis & Bjarne Stroustrup. "The Annotated C++ Reference
Manual". Addison-Wesley, 1990. • Scott Meyers. "Effective C++, 50 Specific Ways to Improve Your
Programs and Designs". Addison-Wesley, 1992. • Scott Meyers. "More Effective C++, 35 New Ways to Improve Your
Programs and Designs". Addison-Wesley, 1996.• J. O. Coplien. "Programmation avancée en C++". Addison-Wesley,
1992.
Le langage C
• langage évolué, typé, structuré• "programmation système"
– Unix– Concision-Efficacité
• Nombreuses bibliothèques• Bonne portabilité• Compilation séparée
Programmation objet en langage C++ 7Département Informatique de l'INSA- Jean-Marc Pierson
Structure d'un programme C++ • PROGRAMME exécutable =
ensemble de "modules objet "(binaire)• Module objet = traduction d'un "texte source"• Texte source = ensemble
– de définitions de classes, fonctions, données– de directives pour le préprocesseur
• Point d'entrée = fonction main( )
Les concepts du langage C++
type utilisateur
classe
donnée : variable ouconstante
expression
instruction
opérateur
type prédéfini
formealgorithmique
exception
héritage
généricité
méthode oufonction
Les concepts du langage C++
type utilisateur
classe
donnée : variable ouconstante
expression
instruction
opérateur
type prédéfini
formealgorithmique
exception
héritage
généricité
méthode oufonction
float CL::f(int a) {float b;b := 1/a; return b;
}
b := 1/a
1/a
/1 et aint, float
div par 0classe CL
Méthode/Fonction • En C++, il existe 2 sortes de fonctions, ayant
un grand nombre de points communs(paramétrage, exécution, surcharge, notation fonctionnelle/opérateur, …)
– les méthodes définies dans une classe et applicables aux objets, instances de cette classe:
objet . Méthode(….)– les fonctions "ordinaires" définies en dehors de
toute classe : fonction(…)les fonctions C sont, bien sûr, dans cette famille, par exemple la fonction "main")
Programmation objet en langage C++ 8Département Informatique de l'INSA- Jean-Marc Pierson
Méthode/Fonction
• Définition dans UN SEUL module source• Appel dans une instruction dans une
méthode/fonction située dans un module source quelconque
• Déclaration dans chaque module où ondésire l'utiliser
( le plus souvent dans un fichier d'interface -de classe ou de module - inclus par #include)
CONTEXTES d'OCCURRENCE d'une méthode/fonction
Exemple: programme C++ simple/* texte source ( compt .C ou compt.cpp) d'un programmecomptant le nombre de lignes du fichier texte lu sur l'entrée standard (utilisation des classes d'E/S standard) */#include <iostream> // lecture des interfaces des classes d'entrées-sortiesint main () // programme principal{ char carac ; int nombreLignes = 0 ;
while (cin . get(carac) ) // tant que l'on n'a pas lu tout le texte // à partir du flot d'entrée standard "cin"
{ if (carac == '\n' ) // si c'est une fin de ligne, on{ ++ nombreLignes ; // incrémente le nombre de lignes}}
cout << nombreLignes <<" lignes\n" ;
// affichage du résultat sur le flot de sortie standard "cout"}
Exécution du programme
% g++ compt.C -o compt Compilation-Reliure du programme compt.C
% compt Exécution avec lecture claviervoila une première ligneet une deuxième
et la dernière ligne (suivie d'un CTRL d)
3 lignes% compt < compt.C Exécution avec lecture fichier disque
15 lignes
Chaîne de production
cc (gcc, g++, …) enchaînent les opérations en fonction : -des options de la commande:
-E : étape 1 -S : étapes 1-2-c : étapes 1-2-3 défaut : étapes 1-2-3-4-0 : optimisation dans l'étape 2
-et des suffixes des fichiers à traiter:. c . C (.cpp) . o
préprocesseurcpp
compilateurc/c++
relieurld
assembleuras
texte sourcemodule
objet programme
1 2 3 4
texte sourceassembleur
Programmation objet en langage C++ 9Département Informatique de l'INSA- Jean-Marc Pierson
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C
• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Le préprocesseur : cpp
• Inclusion de fichier source• Substitution d'identificateurs• Traduction conditionnelle
DIRECTIVES #
Inclusion de fichier source• Rôle : permet d'importer, depuis un fichier
source, dans tout module qui en a besoin, des– définitions de types (classes, . . . ), constantes– déclarations de fonctions
• Syntaxe :#include "cheminAccesFichierAInclure"
(par exemple dans le répertoire de travail)
#include <NomDeFichierPublic>recherche du fichier à inclure dans le(s) répertoire(s) standardexemple UNIX : /usr/include /usr/include/sys . . .
Substitution d'identificateurs(peu utile en C++, à éviter)
• Rôle :– définition d'identificateurs pour traduction conditionnelle– macro-instructions
• Syntaxe :#define identificateur chaineDeCaractères
exemples : #define boucle for( ; ;)#define _MODULEH
#define macro(param1,param2) chaineexemple : #define Afficher(a,b) std :: cout << (a) << (b)
Programmation objet en langage C++ 10Département Informatique de l'INSA- Jean-Marc Pierson
Traduction Conditionnelle• Rôle:
– Aides à la mise au point– Eviter les inclusions multiples de fichier– Gestion de versions
• Syntaxe :#ifdef identificateur
phrases C++ ou directives cpp#endif
• exemples : macro assert (condition) ;#ifdef DEBUGcout << "Mise au point : x =" << x << endl;#endif
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur
• types des données manipulables• classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
les Types des données C++
• Donnée : toute valeur manipulée dans un programme C++, variable ou constante
• Déclaration : association d'un nom et d'un type• Type : caractérise
• la représentation physique (place mémoire)sizeof (type) sizeof variable
• l'ensemble des valeurs possibles• l'ensemble des opérations possibles• la possibilité ou non de modification (préfixe const)
• Définition : déclaration + réservation mémoire
Déclaration• Syntaxe :[const] nomDuType nomDeLaVariable [= valeurInitiale] ;
• Exemples :int nombre ; // type primitifbool trouve = false ; // type primitifconst unsigned int NBCAR = 130 ; // idemstring nomFichier ; // classe standardchar ligne [NBCAR] ; // tableau de type primitifNoeud * racineArbre ; // pointeur sur une classe
Programmation objet en langage C++ 11Département Informatique de l'INSA- Jean-Marc Pierson
Les différents types
• Types primitifs : entiers, énumérations, réels, booléens --> pas de fichiers (classes définies dans la librairie)
• Types dérivés : tableaux, pointeurs, références--> de type quelconque (primitif, dérivé, classe)
• Types définis par l'utilisateur : classes--> définition d'un ensemble d'opérations (méthodes) manipulant
des données, de type quelconque (primitif, dérivé, classe)
--> la solution en C++ pour couvrir tous les besoins spécifiques
• Nom d'alias pour les types : typedef
Types primitifs
• ENTIERS :– de différentes tailles : char, short, int, long– signés ou non : signed (par défaut), unsigned
• BOOLEEN :– bool pouvant prendre les valeurs true, false
• REELS : (virgule flottante)– de différentes précisions : float, double, long double
Les types primitifs (indicatif)char ou signed char 8 bits -128 127unsigned char 8 bits 0 255int (sur proc 32bits) 32 bits –2147483648 2147483647unsigned int 32 bits 0 4294967295short intshort 16 bits -32768 32767unsigned short intunsigned short 16 bits 0 65535long intlong 32 bits –2147483648 2147483647unsigned long intunsigned long 32 bits 0 4294967295float 32 bits 1.175 E – 38 3.402 E + 38double 64 bits 2.225 E – 308 1.797 E + 308
Enumération• Permet de définir un nouveau type (sorte d'entier) ne
pouvant prendre que des valeurs désignées par des noms ex : enum Couleur { ROUGE, VERT, ORANGE} ;//une variable de type Couleur ne peut prendre qu'une des valeurs constantes :// ROUGE (0) VERT (1) ORANGE (2)// définition d'une variable de type COULEUR
Couleur feux = ROUGE ;
feux = 1 ; //affectation erronée
• On peut forcer les valeurs (autres que 0,1,2, . . . , de type char, short, int . . . ):
enum Taille { GRAND=100, MOYEN =10, PETIT=1} ;
• On peut simplement regrouper des noms de constantes:enum {OK, SATURATION, DOUBLE_DEFINITION} ;
Programmation objet en langage C++ 12Département Informatique de l'INSA- Jean-Marc Pierson
Types dérivés• TABLEAU : collection ordonnée de N (constante) éléments
de même type (quelconque : primitif, dérivé, classe), accessibles par leur rang (0 . . N-1) : [ ]
• POINTEUR : donnée contenant l'adresse d'une donnée d'un certain type : *
• REFERENCE : nom alternatif pour un objet (surtout utilisé pour le passage d'arguments à une fonction et le retour du résultat d'une fonction) : &
Tableau• Initialisation possible par une suite de valeurs• Accès à un élément par l'opérateur d'indexation [ ]• Possibilité de tableau de tableau de . . . • Le nom d'un tableau T désigne l'adresse de son premier
élément : – T est équivalent à l'adresse du 1er élément notée &T[0]
• La classe standard « vector » est une généralisation du type tableau, donc à utiliser préférentiellement
• En C, les chaînes de caractères sont représentées par des tableaux de char . En C++, on préfère utiliser la classe standard « string »
Pointeurs• Usages :
– accès à des objets créés à la demande, donc implantés dynamiquement en mémoire centrale
– parcours séquentiel d'un tableau – modification depuis une fonction des variables de la fonction appelante
(alternative : passage par référence)
• Accès à – l' objet pointé par *– un membre (méthode ou attribut) de l'objet pointé par ->– un élément i d'un tableau pointé par [i]
• Attention à la signification de l'affectation !
Lien pointeur/mémoire
int i;
i = 3;
int *pi;
pi = & i;
@ MémoireContenu de la
mémoire
// ici, on a pi=&i=0xff00 et *pi=i=3
3
0xff00
0xff00
0xff03&pi
Ici, on dit que l ’on déréférence pi
Programmation objet en langage C++ 13Département Informatique de l'INSA- Jean-Marc Pierson
Lien pointeur/mémoire (suite)int T[]={3,10,100,22};
int *pT, *pi;
pT = T;
pi = &T[2];
Adresses mémoire
Contenus de la mémoire
Zone mémoire réservée pour le
tableau T
30xff0010100
22
// pT = T = &T[0] = 0xff00 et *pT= T[0] = 3
// pi = &T[2] = 0xff02 et *pi = T[2] = 100
0xff05
0xff06&pT&pi
0xff00
0xff02
Exemples de types dérivésconst int LGMAX = 250 ; char ligne [LGMAX] ; const int LIGNES = 12 ; const int COLONNES = 6 ;double matrice [LIGNES] [COLONNES] ;const long PUISS10 [ ] = { 1 , 10 , 100 , 1000 } ;
char * ptr = ligne ; // ptr contient l'adresse d'un char (&ligne[0])
char * liste [ N] ; // liste est un tableau contenant N pointeurs de char
// jour est un tableau de 7 string constantesconst string jour [ ] = { "lundi", "mardi",
"mercredi","jeudi", "vendredi","samedi", "dimanche"} ;
Les références• N’existent pas en C• Permettent de créer des synonymes
d’identificateurs• Sont toujours initialisées à leur déclaration• exemple :int i; // i est un entier
int &ri=i; // i est une référence sur l’entier i
ri = ri+1; // équivalent à i=i+1
• i et ri font références à la même variable
Lien pointeurs/références• Déjà vu sur la manipulation de pointeurs :int i=0;int *pi=&i;*pi=*pi+1; // Manipulation de i via pi.
• Si on fait passer l'opérateur & de la deuxième ligne à gauche del'opérateur d'affectation :
int i=0;int &* pi = i; // Cela génère une erreur de syntaxe mais nous l'ignorons pour les besoins de l'explication.
*pi=*pi+1;
• En utilisant des références :int i=0;int &ri=i;ri=ri+1; // Manipulation de i via ri.
Programmation objet en langage C++ 14Département Informatique de l'INSA- Jean-Marc Pierson
Allocation dynamique de mémoire : opérateurs new/delete
Exemple :T * p1= new T ; // T est un type primitif ou une classe
// p1 pointe sur l'élément de type T qui a été créé
int nombreElements ;. . . . . . . . // calcul de nombreElements
T * vecteur = new T [nombreElements ] ;// création d'un tableau de "nombreElements" T// vecteur pointe le premier élément si création OK// vecteur[i] désigne le ième élément// si la création est impossible, exception bad_alloc
delete p1 ; // libération d'un élément isolé
delete [] vecteur ; // libération d'un tableau d'objets
Définition d'alias pour un type existant : typedef
• Syntaxe :typedef nomTypeExistant NouveauNom ;
• exemples :
typedef unsigned int nombrePositif;
typedef std::map<string,string> lexique ;
typedef Noeud * ARBRE ;
• Utilisation nombrePositif n = 3;
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions
• portée des noms/durée de vie des objets• fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Portée des noms
PROGRAMME : global
"namespace"
classe
fonctionbloc
Programmation objet en langage C++ 15Département Informatique de l'INSA- Jean-Marc Pierson
Portée des noms• Pour un nom déclaré dans une fonction
portée limitée au bloc de sa déclaration ( à privilégier)
• Un nom déclaré dans une classe M (attribut, méthode, constante,type) appartient à l’espace de noms de la classe . – Il est visible depuis le corps des méthodes de la classe . – A l ’extérieur l’opérateur de portée M:: est nécessaire (sauf si le contexte
permet d'identifier M, par ex : instanceDeM . nomMethode(… . ) )
• Un nom déclaré dans un module (« namespace ») N appartient à cet espace de noms . – Il est visible par toutes les classes de ce namespace . – A l ’extérieur l ’opérateur de portée N :: est nécessaire
• Les autres noms sont globaux (à éviter)
Portée des noms (suite)• Les variables peuvent être déclarées n'importe où dans un
bloc.…{
int x;…{
int y;…}…
}...
porté de y porté de x
Une seconde variable x dans le second bloc ne peut pas être déclarée.
• Créer un namespace en C++ a pour but de définir un ensemble de variables, de classes et de fonctions partageant un même espace de nommage.
• Dans un espace de nommage, deux variables globales ou deux fonctions globales ou deux classes ne peuvent pas avoir le même nom.
• Un espace de nommage peut être défini par morceaux.• Une variable, une fonction ou une classe définie dans un
espace de nommage peut être utilisée dans un autre espace en spécifiant l’espace d’appartenance (avec l'opérateur ::)
Namespace Espace de noms
namespace std{ // définitions de classes, de fonctions, d'objets standard…
// par exemple :ostream cout ; // flot de sortie standard
...}
// utilisation de l'identificateur "cout" du "namespace" std :std::cout << "OK" ;
// ou // ouusing namespace std ; using std::cout ;cout << "OK" ; cout << "OK" ;
Programmation objet en langage C++ 16Département Informatique de l'INSA- Jean-Marc Pierson
Espace de nom, opérateur ::
namespace A {void f();
}
namespace Bvoid f();
}
#include "A.h"#include "B.h"
void main() {A::f();B::f();
}
A.h
B.h
main.C
Espace de nom (suite...)
namespace A {void f();
}
namespace Bvoid f();
}
#include "A.h"#include "B.h"
using namespace A;
void main() {f(); // ok, f() n ’est connu
// que dans l ’espace // de nom A
B::f();}
A.h
B.h
main.C
Espace de nom (suite et fin)
namespace A {void f();
}
namespace Bvoid f();
}
#include "A.h"#include "B.h"
using namespace A;using namespace B;
void main() {f(); // non, ambiguïté !
}
A.h
B.h
main.C
?
?
Implantation mémoire des variables• Locales à un bloc d'une méthode/fonction : 3 modes d'allocation
– par défaut (auto)- implantation en mémoire dynamiquement (à l'exécution)
dans la zone "pile d'exécution"- initialisation possible par une expression variable
(ou une "suite d'expressions variables" si tableau)– en registre (register)
- implantation dynamique dans un des registres de l'UC– implantation statique en mémoire (static) à la compilation
• Globales (au programme)– implantation en mémoire statiquement– initialisation possible
Programmation objet en langage C++ 17Département Informatique de l'INSA- Jean-Marc Pierson
Durée de vie des objets
La durée de vie dépend du type de l’objet :• local à un bloc : créé à sa définition, détruit à la sortie
du bloc . • statique : créé au début de l'exécution du programme,
détruit à sa fin . • dynamique : créé et détruit sous contrôle du programme
(new/delete)• attribut d'un autre objet : créé (détruit) lors de la
construction (destruction) de l'objet contenant .
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets
• fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Surcharge de fonctions ordinairesC++ permet de définir des fonctions homonymes, c'est-à-dire de même nom, mais avec des listes de paramètres différentes. L'opération"nomFonction (liste arguments)" est identifiée par :nomFonction + nombre arguments + type arguments
Le compilateur C++ "calcule" un identificateur correspondant à l'ensemble, pour la génération du code objetExemple de 3 fonctions C++ homonymes mais distinctes :int traduire(int,int,int); // version 1
void traduire(int,int); // version 2
void traduire(int,char *); // version 3
// mais
int traduire(int,int);// erreur, car ambiguité avec la version 2 : le type de retour n'est pas pris en compte
Appel de fonctions C par un programme C++
Le codage utilisé par C++ pour identifier les fonctions appelées impose une déclaration spéciale pour reconnaître les fonctions écrites dans d'autres langages .
extern "C" char * strcpy ( char*, const char *) ;
ouextern "C"
{ < déclaration fonction1 >< déclaration fonction2 >
. . . . . . } ; // ceci est fait en général, dans les fichiers . h
Programmation objet en langage C++ 18Département Informatique de l'INSA- Jean-Marc Pierson
Programmation Modulaire
Interface
Définition de classe
Définition de constantes
Déclarations de fonctions exportées
module1 . h
Réalisation#include "mod.h"Réalisation de classeDéfinitions des fonctions
exportées
module1 . C
#include "mod.h" Module 2 (ou programme principal)utilisantmodule1
module1
Programmation modulaire
• Le code source d'une classe est, en général, divisé en deux fichiers : – fichier d'entête, déclaration (header file, généralement .h) : contient
la déclaration et une partie de la définition d’une classe ; nécessaire pour l'utilisation du module
– fichier de définition/réalisation (généralement .C, ou .cxx, ou .cpp) :contient la définition des fonctions membres et d’une partie des données membres (pour les classes), sinon la définition des fonctions
• Il est recommandé (mais pas imposé) de ne mettre qu'une classe par fichier
Bibliothèques, création
• On peut regrouper plusieurs fichier objet dans une bibliothèque regroupant des fonctionnalités : collection de fichier objet (.o)
• Création de fichier .a (bibliothèque statique) ou de .so (bibliothèque partagée) sous unix(exemple : libm.a, pour la bibliothèque mathématique sous Unix, grâce à l'utilitaire ar) ou de .dll sous windows
Bibliothèques, utilisation• Utilisation dans le fichier source du
programme :
• Utilisation à la compilation:g++ -o main main.C -lm
#include <iostream>#include <cmath>void main() {
cout << "la racine carré de 9 vaut : " << sqrt(9);}
En fait, inutile ici car g++ l’inclut automatiquement
Programmation objet en langage C++ 19Département Informatique de l'INSA- Jean-Marc Pierson
Bibliothèques
flots C++
fonctionsmathématiques C
fonctionsstandard C
bibliothèquede composants C++
Fichiers d'interfacesou d'entêtes
fstream
vector list string map
iostream
algorithm
cstdio cstring
cstdlibfcntl . h unistd . h
ctime
cmath
Fichiers archives ( . a)collection de . o
Interface avec le système L'accès aux primitives du système d'exploitation se fait par des
appels de fonctions de la bibliothèque, qui assurent l'interfaceavec le noyau .
Pas de différence syntaxique entre une fonction d'une bibliothèque d'accompagnement et une primitive du noyau .
exemple :primitives : open() read() fork()fonctions C: strcpy() sqrt()méthodes : istream::get()
Paramètres du "main"Le point d'entrée d'un programme exécutable (en général, la
fonction "main") peut être paramétré par une liste d'arguments :chaînes de caractères communiquée par la primitive système de lancement de l'exécution (exec sous Unix)
Paramètres :- entier donnant le nombre de chaînes (>=1)- tableau de pointeurs sur les différentes chaînes
int main (int nbreArguments, char * liste[]){ // accès au ième (1,2,3 . . . ) argument par liste[i]
// accès au nom du programme par liste[0]// accès au dernier argument par liste[nbreArguments-1]// . . . . . . . .
}
ExempleSupposons que l'on demande l'exécution du programme
"main" (dont le main a la définition précédente) par la commande:
% main donnees 5 tablenbreArguments = 4liste[0] = "main"liste[1] = "donnees"liste[2] = "5"liste[3] = "table"
Programmation objet en langage C++ 20Département Informatique de l'INSA- Jean-Marc Pierson
Mécanisme inline
• Les méthodes (ou fonctions) inline sont les méthodes dont le corps (la définition) est directement écrit dans la déclaration de la classe (fichier header) ou précédé par le mot-clé inline et écrit dans le fichier de réalisation (.C)
• Si une méthode est inline alors le compilateur insérera le code propre de la méthode au lieu d’utiliser une instruction d’appel à la fonction.
Mécanisme inline
• Les fonctions/méthodes inline doivent être utilisées seulement pour des fonctions/méthodes dont le code est très court.
• Avantage : efficacité en temps d'exécution• Inconvénients :
– taille code objet généré par la compilation– non masquage de la réalisation (Rappel : les programmes
utilisateurs d'une classe ou d'une fonction doivent avoir la vue sur le fichier header, pour avoir leur déclaration)
Méthodes/Fonctions inline
// classe Aclass A {
private:int m_a; // variable privée de classeA
public:// fonctions d'accès à la variable privée m_aint getA() const { return m_a; }inline void setA(int p_a);
};
// fonction qui renvoie le maximum de deux entiersinline int max(int a,int b)
{ return a<b?b:a; }
classeA.hclasseA.C
Une fonction (pas une méthode, donc déclarée en dehors de toute classe) peut aussi être inline(cas de max() ici). A chaque appel de celle-ci, elle sera remplacée par son code.
Une fonction directement écrite dans la déclaration de la classe est inline. (cas de getA() ici). Certains compilateurs ne la considèrent pas inline si elle est trop longue (utiliser alors le mot-clé inline).
// implémentation de la classe classeAvoid classeA::setA(int p_a) {
m_a=p_a;}
L’utilisation du mot clé inlinepermet de cacher l’implémentation de la méthode tout en profitant des avantages des fonctions inline
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques
• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Programmation objet en langage C++ 21Département Informatique de l'INSA- Jean-Marc Pierson
Instructions, vue générale• Définition : type nom [initialisation] ;
• Instruction simple : expression ;
• Bloc : { suite d'instructions }• Instructions conditionnelles : if switch
• Instructions itératives : while do forbreak continue
• Retour de fonction : return
• Lancement d'une exception : throwSaut : goto
Instruction if// première formeif (condition) // condition : expression_entière ou booléenne
// ou TYPE var = expression_entière ou booléen{ suite-instr}// deuxième formeif (condition){ suite-instr1}else{ suite-instr2}
Booléens en C• ... n'existent pas ! • en C, la gestion des conditions (vrai/faux) se
fait se la manière suivante :– une expression est fausse si son évaluation donne
0– sinon l'expression est vraie !
int a = 3;if (a = = 3) {
// vrai }
if (int a=3) { // vrai
}
Instruction switch
switch (expression_entière){ case valeur1 : suite instr1 ;
break ;case valeur2 : suite instr2 ;
break ;. . . . . . default : suite instr ;
}
break ; : en fin de "suite instr i" pour passer à l'instruction suivant le switch
Programmation objet en langage C++ 22Département Informatique de l'INSA- Jean-Marc Pierson
Les instructions itératives (1)Tant que
while (condition) {suite instructions;
}
Tant que la condition est vraie, exécuter les instructions du bloc
do {suite instructions;
}while (condition);
Exécuter les instructions du bloc tant que la condition est vraie
Les instructions du bloc sont exécutées au moins une fois. La condition est évaluée après cette première exécution.
Les instructions itératives (2)Répéter
Les instructions itératives (3)Pour
for (initialisation; condition; incrémentation){suite instructions;
}
Tant que la condition est vraie, exécuter les instructions du bloc
Exécution de l’instruction d’incrémentation de la ou des variables de boucle après la suite d'instructions
Initialisation de la ou des variables de boucle
Les instructions itératives(complément)
• en C++, la ou les variables de boucle peuvent être déclarée dans l’instruction for.
for(int i=1;i<=10;i++) {...}
• L’opérateur , peut être utilisé entre autres pour les parties initialisation et incrémentation dans le cas où elles nécessiteraient plusieurs instructions.
for (i=1,j=1; ...; ...) {...}
Programmation objet en langage C++ 23Département Informatique de l'INSA- Jean-Marc Pierson
Lien entre instructions itérativesfor (i=1;i<=10;i++) x=x+i;
i=1
i<=10 ?
x=x+i
i++
OUI
NON
i = 1;while (i<=10) {
x=x+i;i++;
}
i = 1;if (i<=10) {
do { x=x+i;i++;
}while (i<=10);
}
Instruction itératives : coupures de boucle
BREAK et CONTINUE– break stoppe une boucle (par exemple, une
boucle infinie : la condition d’arrêt est définie à l’intérieure de la boucle et si la condition se réalise alors l’instruction break sort de la boucle et passe à l'instruction suivant la boucle)
– continue passe automatiquement à l’itération suivante sans exécuter les instructions suivantes de la boucle
Coupures de boucle (exemple)int i=0, x=0; while (true) {i++;if (i>10) break;if (i=>5 && i<=8) continue;x = x + i;
}cout << "i=" << i << "x=" << x;
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions
• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Programmation objet en langage C++ 24Département Informatique de l'INSA- Jean-Marc Pierson
Expressions/opérateurs
expression : Combinaison d'opérandes à l'aide d'opérateurs . opérande : constante ;
variable ; // de type primitif, dérivé ou classe
expression . opérateur : opérateur prédéfini ;
opérateur défini par l'utilisateur .
L'évaluation de la valeur de l'expression est éventuellement précédée par des conversions des valeurs de certains de ses opérandes.
Constantes littérales • Numériques :
entières base 10 : 56base 8 : 075base 16 : 0xba7f
réelles (double précision)3.14 5.32e-2
• Entier codé sur 8 bits (ou 16 bits pour code étendu :"Unicode"):
caractère imprimable : 'a' ' ;'spécial : '\n' '\0' '\033' '\0x7a'
Les opérateurs sur entiers
Numériques+ - * / %
Comparaison== != > >= < <=
Logiques! && ||
(not and or)
bit à bit& | ^ ~>> <<
Affectation=
+= -= *= /= <<= >>= , … .
entiers
Les opérateurs sur réels
réels
Numériques+ - * /
Comparaison== != > >= < <= Affectation
=+= -= *= /=
Programmation objet en langage C++ 25Département Informatique de l'INSA- Jean-Marc Pierson
Incrémentation/Décrémentation
Sur entiers, réels et pointeurs, l'affectationvariable = variable +1
peut se raccourcir envariable++ ou en ++variable
post-incrémentation pré-incrémentation(valeur expression= variable) (valeur expression = variable+1)
idem avec -- pour la (post/pré)-décrémentation . Signification de l'opération " pointeur + 1 "Noter la différence entre *ptr++ et *++ptr
Expression conditionnelle condition ? expr1 : expr2
désigne une expression dont la valeur est expr1 si condition est vraieexpr2 sinon
// exemple : transformation d'un entier en code ASCII
unsigned char c ;// c est supposé contenir une valeur comprise entre 0 et 15
unsigned char cHexa = c + ((c >9) ? 'a'-10 : '0') ;// cHexa contient le code ASCII de la représentation hexadécimale de c
Chaînes de caractères littérales
• Exemples :"bonjour""\tResultats\n\t---------\n""Ceci " "est" " une" " seule" " chaine"
• Représentation physique :tableau de caractères terminé par le caractère nul ('\0')
Attention : Ne pas confondre 'a' avec "a"
• "bonjour" est de type const char [ 8 ]
Opérateurs sur tableaux
tableaux
accès au premier élément* tab
L ’affectation n'existe pas
accès à un élément
tab[ i ]
Rappel : tab = &tab[0]
Programmation objet en langage C++ 26Département Informatique de l'INSA- Jean-Marc Pierson
Opérateurs sur pointeurs
pointeurs
Addition/soustractiond'un entier à un pointeur
ptr +/- i
Comparaison== != > >= < <= Affectation
=+= -=
accès à l'élément pointé*ptr
ptr[ i ]*(ptr+i)
accès à un membrede l'objet pointéptr -> membre
Ordre de priorité sur les opérateurs
• Les opérateurs respectent l’ordre de priorité du C
.[ ]*( )
++--!~
*/%
+-
<<>>
<><=>=
==!= & ^ && ||?: =
Du moins en moins prioritaire
Pointeur et tableau • Nom d'un tableau = pointeur sur son premier élément• Accès aux éléments par opérateurs: * []• exemples:
char c ; char * ptr; char ligne [LGMAX];ptr = &c ; // opérateur "adresse de"ptr = ligne ;c = *ptr ;c = * (ligne+2) ; // addition d'un entier à un pointeur++ptr[-1];
• Différences :sizeof ligne=LGMAXsizeof ptr = 4
sizeof (char *) = 4sizeof (char) = 1
Pointeur et tableau ( suite )
Exemples de déclarations équivalentes :
void Calcul (char * ligne) ;
void main (int nbArg, char * liste[]) ;
void Calcul (char ligne []) ;
void main (int nbArg, char * *liste) ;
Programmation objet en langage C++ 27Département Informatique de l'INSA- Jean-Marc Pierson
• Le mot-clé const peut être utilisé avec les pointeurs.• Deux syntaxes = deux significations bien différentes
– le contenu de la zone mémoire pointée ne peut pas être modifiée :const int * x; ou int const * x;
autorisé : x=&y; illégal : *x=1;– la valeur du pointeur ne peut pas être modifiée :
int * const x;
autorisé : *x=1; illégal : x=&y;– rien ne peut être modifiée :const int * const x; ou int const * const x;
illégal : x=&y; et *x=1;
Pointeurs et const
La deuxième forme est plus claire. const est placé à droite de ce qui ne peut pas être modifié.
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques
• héritage• compléments : exceptions/conversions/"friend"• La librairie standard C++
Généralités sur l'héritageDe nombreuses classes peuvent être conçues comme des
spécialisations de classes plus générales (relation EstUn ou SorteDe) .
L'héritage permet d'éviter de redéfinir dans une classe dérivée le comportement des classes ancêtres, et donc, de ne se préoccuper que du comportement particulier à la classe .
On organise les classes selon une hiérarchie (arbre d'héritage ou graphe si héritage multiple) .
Généralités (suite)• principe de SUBSTITUTION
Sémantique de l'héritageSi on a A <== . . . <==B ( B hérite de A)
alors B doit pouvoir s'employer partout où A est employé : Attention : l'inverse n'étant pas vrai
• Sous Typage (relation de préordre sur les types)Les descendants d'une classe en sont des sous-types . Si on a A <== B <== C <== . . . , tout objet instance d'une classe héritant de A (donc de classe A, B, C, . . . ) est de "type A" . On peut donc lui appliquer toutes les opérations définies dans la classe A .
Programmation objet en langage C++ 28Département Informatique de l'INSA- Jean-Marc Pierson
Arbres d'héritage
Collection Forme
Ligne
Cercle Carré
RectangleSéquence
Pile DictionnaireFile
Non_séquentielleEllipse
Principe de substitution : toute opération applicable à une instance de Forme doit être applicable à une instance de Ligne, Ellipse, Cercle, . .
Ensemble
Héritage en C++
class classeDérivée : [mode] classeDeBase
{ // compléments d' interface pour "classeDérivée"} ;
mode = public cas le plus fréquentprivate pour héritage partielprotected
Exemples d'héritage// Définition de la classe pixel par dérivation de la classe point
class Pixel : public Point // un pixel est un point
// ou une sorte de point
{ public :enum Couleur {NOIR, ROUGE, BLANC} ;Pixel(Couleur laCouleur, int abs, int ord);
// la construction d’un Pixel s’appuie sur la construction d’un Point : pas de constructeur particulier
void Colorer ( Couleur laCouleur = NOIR) { coul = laCouleur ;}
protected : Couleur coul ;
} ;
Visibilité des éléments héritésLe mode d'héritage conditionne la visibilité, dans la classe
dérivée, des éléments ( attributs et méthodes) hérités de la superclasse .
• Héritage public : accès aux "public" et aux "protected"• Héritage private : tous les éléments deviennent "private", mais on
peut indiquer explicitement les éléments "public" que l'on souhaite laisser "public", donc accessibles aux clients de la classe dérivée .
Utilisation de l'héritage pour réutilisation de code et non de comportement .
• Héritage protected: les éléments "public" deviennent "protected", les autres sont inchangés
Programmation objet en langage C++ 29Département Informatique de l'INSA- Jean-Marc Pierson
• class B : public A {…};– un objet de type B (ou un pointeur sur…) pourra toujours être vu comme un
objet de type A (ou comme un pointeur sur…)– accès depuis B aux données public et protected de A.
• class B : private A {…};– un objet de type B (ou un pointeur sur…) pourra être vu comme un objet de
type A (ou comme un pointeur sur…) depuis B ou les amis de B (« seuls B et ses amis savent que B hérite de A »).
– les données et fonctions public et protected de A ne sont pas accessibles dans les sous classes de B.
• class B : protected A {…};– un objet de type B (ou un pointeur sur…) pourra être vu comme un objet de
type A depuis B, les amis de B et les sous-classes de B.
Héritage et visibilité Héritage et visibilite
B hérite de A Dans B Héritagepublic protected private
public Oui Oui Ouiprotected Oui Oui Oui
Membre de A
private Non Non Non
B hérite de A A l’extérieur Héritagepublic protected private
public Oui Non Nonprotected Non Non Non
Membre de A
private Non Non Non
Appels des constructeurs/destructeurs
Classe A
Classe B
Classe C
Pour un objet de classe C (qui hérite de B qui hérite de A)
Appel de A( )
puis de B( )
puis de C( )
A la destruction
Appel de ~C( )
puis de ~B( )
puis de ~A( )
A la création
Liaison entre constructeursSi le constructeur de la superclasse a des arguments, on doit préciser,
avant le corps des constructeurs des classes dérivées (dans l'interface si "inline", sinon dans la réalisation de la classe), quels arguments lui transmettre, avec une syntaxe similaire à l'initialisation des attributs .
exemple:class Pixel : public Point{ public:
Pixel ( Couleur couleur, int abs = 0, int ord = 0) : Point(abs,ord), coul(couleur) {}// . . . . | |// . . . . appel du constructeur initialisation de l’attribut de Pixel
};
Programmation objet en langage C++ 30Département Informatique de l'INSA- Jean-Marc Pierson
Exemples d'héritage (1/2)#include "Point.h"class Forme{ public :
void Deplacer (Point vecteur) ;void Dessiner () const ; //définition?
Forme (Point orig) : origine(orig) {}~Forme() ;
protected : Point origine ;
} ;
Exemples d'héritage (2/2)class Rectangle : public Forme
// un Rectangle est une Forme{ public :
void Dessiner() const ; // redéfinitionRectangle ( Point basGauche, long longueur, long hauteur) : Forme (basGauche), diagonale (longueur, hauteur) {}~Rectangle() ;
protected : Point diagonale ; // attribut supplémentaire
};
class Carre : public Rectangle // un carré est un Rectangle{ public : Carre ( Point orig, long cote)
: Rectangle(orig , cote , cote) {}} ; // pas d'attribut ni d ’autre méthode spécifiques à Carre
Affectation d'objets/* supposons que la classe Point soit munie d'un constructeur
Point (int abs, int ord) ;et que la classe Pixel qui hérite de Point ait un constructeur
Pixel (Couleur laCouleur, int abs, int ord) ; */
Point p (1,2) ;
Pixel px (Pixel::NOIR, 3, 5);p = px ; // autorisé, affectation partielle
// p demeure un Point ; p est en (3,5)
px = p ; // interdit
//Noter que le type Couleur étant défini dans l'espace de noms de Pixel,// on doit préciser cette appartenance dans l'écriture des valeurs du type Couleur, comme ici "Pixel :: NOIR"
Affectation de pointeurs d'objets
Point p(1,2), * pp ;Pixel * ppx ;
pp = new Pixel ( Pixel::BLANC, 4 , 8);
// autorisé, car on peut affecter à un pointeur de Point// l'adresse d'un objet d'une classe descendante// mais
pp->Colorer( ... ); // est interdit !! En effet pp reste un point !
ppx = &p; // de même, ceci est interdit !// ppx ->Colorer( Pixel :: ROUGE) ???
Programmation objet en langage C++ 31Département Informatique de l'INSA- Jean-Marc Pierson
• Le comportement du constructeur par recopie est différent selon que les constructeurs par recopie des classes de base (A) et dérivée (B) existent ou non.
• La classe dérivée (B) n'a pas de constructeur par recopie :– il y a donc appel au constructeur par recopie par défaut de B. Cela provoque
l'appel du constructeur par recopie de A. Si A n'a pas de constructeur par recopie, le constructeur par recopie par défaut est utilisé.
• La classe dérivée (B) a un constructeur par recopie :– si celui-ci fait appel au constructeur par recopie de A dans son en-tête (B(B& x):A(…) { }), alors celui-ci sera appelé. Sinon le constructeur sans
argument de A sera appelé.
Constructeur par recopie• Supposons que B hérite de A et considérons
l’affectation entre objets de type B.• Si B surcharge l’opérateur =, on ne fera appel qu’à
ce dernier.• Si B ne surcharge pas l’opérateur =, on fera appel à
l’opérateur = de A (surchargé ou par défaut) pour les attributs hérités de A et à l’affectation par défaut pour les autres.
Héritage et affectation
Affectation d'objets/* supposons que la classe Point soit munie d'un constructeur
Point (int abs, int ord) ;et que la classe Pixel qui hérite de Point ait un constructeur
Pixel (Couleur laCouleur, int abs, int ord) ; */
Point p (1,2) ;
Pixel px (Pixel::NOIR, 3, 5);p = px ; // autorisé, affectation partielle
// ici, c'est l'opérateur d'affectation de la classe Point qui est utilisé (surchargé ou par défaut) : le Pixel est converti enPoint, puis l'affectation se fait
Spécialisation par redéfinition de méthodesclass Point{ public : virtual void Afficher ()
{ cout << x <<"," << y <<endl ; }protected :
int x, y; // x et y sont visibles des classes descendantes};class Pixel : public Point { public :
virtual void Afficher () // redéfinition de afficher{ cout << x <<"," << y << "couleur:" << coul
<<endl ;}// on aurait pu réutiliser la méthode de l'ancêtre, avec le corps suivant :// { cout << "couleur:"<<coul<<" " ; // Point :: Afficher() ; }} ;
Programmation objet en langage C++ 32Département Informatique de l'INSA- Jean-Marc Pierson
Différence entre ...surcharge et redéfinition
• Surcharge : on définit une méthode ayant le même nom qu'une autre déjà définie (dans la même classe ou une classe parente) mais des paramètres différents
• Redéfinition : on définit une méthode ayant la même signature (nom+paramètres+code retour) qu'une méthode définie dans une classe parente
Liaison statique/dynamiquePoint * pt = new Point ( 3 , 5 ) ;
pt -> Afficher() ; // appel de la méthode Point :: Afficher()
pt = new Pixel ( ROUGE , 4 , 8) ;
pt -> Afficher () ; // appel de la méthode Pixel :: Afficher()
Si l'on n'avait pas déclaré la méthode Afficher virtual dans la classe de base, on aurait eu une liaison statique et donc un appel à Point::Afficher() au lieu de Pixel::Afficher().
Pour obtenir un lien dynamique, on doit mettre l'attribut virtual dans la déclaration de la méthode, dans l'interface de la classe de base :virtual typeRetour NomMéthode (listeParamètres) ;
// NomMethode ne peut être redéfinie dans les descendants // qu'avec la même liste de paramètres et le même type de retour
Danger de la liaison statiqueclass Point{ public :
...void Afficher() ;void Deplacer(int dx, int dy) {
x += dx ; y +=dy ; Afficher(); }
...} ;
class Pixel : public Point{ public : Pixel(Couleur, int, int);void Colorer (Couleur) ;void Afficher() ;
protected : Couleur c ;
} ;
Point p ( 1 , 5 ) ;Pixel px ( ROUGE , 4, 8 ) ;p . Afficher(); // affiche 1, 5px . Afficher(); // affiche 4, 8, couleur:rougep . Deplacer ( 1,1 ) ; // affiche 2, 6px . Deplacer( 1,1 ) ; // affiche 5, 9// car c'est la méthode Point :: Afficher qui a été appelée !!!// Remède : virtual void Afficher() dans Point
Le polymorphisme
• Concept de la théorie des types, selon lequel un nom d’objet peut désigner des instances de classes différentes issues d’une même arborescence
• Étroitement associé à l’interaction entre l’héritage et la liaison dynamique
• Une même opération peut se comporter différemment sur différentes classes issues de la même arborescence
Programmation objet en langage C++ 33Département Informatique de l'INSA- Jean-Marc Pierson
Le polymorphisme
class Instrument { …public:void off() {…}void play() {
cout << "Instrument.play()" << endl;}
};
class Wind : public Instrument { …public:void play() {
cout << "Wind.play()" << endl;}
};
void main() {Wind x;
((Instrument*)&x)->play();x.play();
}
Instrument *x=new Wind();x->play();
?
x est un instrument.
Ligature statique (Early binding)
Le polymorphisme
flûte est un instrument de musique à vent dont flûte est un Instrument.
L’appel à play considère le type réel de l’instrument (ici Wind) et fait donc appel à la fonction play de Wind.
Cette « recherche » est effectuée pour toute fonction redefinie et virtuelle.
class Instrument { …void off() {…}virtual void play() {
cout << "Instrument.play()" << endl;}
};
class Wind : public Instrument { …virtual void play() {
cout << "Wind.play()" << endl;}
};
void main() {Instrument *flute=new Wind();flute->play();
}
Ligature dynamique (Late binding)
Le polymorphisme• Techniquement, comment ça marche ?• Toute instance dispose d’une référence sur une table qui
associe le nom des fonctions et l’emplacement du code des fonctions.
• Il existe une table par classe.
void play(…) {…}Wind
void play(…) {…}Instrument
flûte…off
play...
Wind
void off(…) {…}Instrument
La fonction off n’est pas redéfinie.
• Il est conseillé de déclarer les destructeurs virtuels.
Destructeur et polymorphisme
class Instrument {...virtual ~Instrument() {...}
};
void main() {Instrument *flute=new Wind();
flute->play();delete flute;
}
1
2
class Wind : public Instrument { ...
virtual ~Wind() { ... }};
Programmation objet en langage C++ 34Département Informatique de l'INSA- Jean-Marc Pierson
Exemple de polymorphisme
Forme
Ligne RectangleCercle Dessin
virtual void Deplacer() ;virtual void Dessiner() const=0 ;
Ligne( ) ;virtual void Dessiner() const ;
Cercle() ;virtual void Dessiner() const ;
Rectangle() ;virtual void Dessiner()
const ;
/* un Dessin est une liste de Formes :structure de donnéespolymorphe*/Dessin() ;virtual void Deplacer();virtual void Dessiner()
const;void Ajouter(Forme *) ;
classe de base abstraite
Classes abstraitesLe seul but de certaines classes est de servir uniquement de classes
de base, et non d'être instanciables : on parle de
classes abstraites ( cas de Forme ci-dessus)En C++, une classe est considérée comme abstraite, si sa définition
contient une méthode virtuelle pure . Exemple, pour Forme,virtual void Dessiner() = 0 ;
==> le compilateur C++ interdit d'instancier la classe Formeet vérifie que tous ses descendants redéfinissent la méthode
virtual void Dessiner ()Une classe n'ayant que des méthodes virtuelles est une spécification
d'un type abstrait (TA) : noms et signatures des opérations imposés pour toutes les classes d'implémentation
Forme canonique d'une classe class X{ public : // méthodes publiques
// . . . . . . . . . . . // autres méthodes
X & operator = ( const X &) ; // affectation
X () ; // constructeur par défaut
X (const X &) ; // constructeur de copie
virtual ~X () ; // destructeur
private : . . . . . . // attributs privés de X
protected : . . . // attributs accessibles à X et à ses descendants
} ;
Création d'une classe simple par héritage d'un exemplaire de classe générique
On peut combiner héritage et généricité . Exemple :template <class T> // Point est une classe génériqueclass Point { public :
Point (T abs=0, T ord=0): x(abs),y(ord) {};void Afficher() ;
protected : T x,y ;
} ;class Pixel : public Point<int> // Pixel hérite de l'exemplaire Point<int>{ public :
Pixel (Couleur coul, int abs = 0 , int ord = 0): c(coul), Point <int> (abs,ord) {};
protected : Couleur c ;} ;
Programmation objet en langage C++ 35Département Informatique de l'INSA- Jean-Marc Pierson
Création d'une classe générique par héritage
On peut obtenir une classe générique par héritage d'une classeExemples :template <class T> // héritage d'une classe simple Bclass A : public B{
// . . .} ;
template <class T> // héritage d'une classe génériqueclass Vecteur : public Vect<T> {
// . . .} ;
L’héritage multiple
• En C++, l’héritage peut être multiple.
• Une instance de la classe C hérite à la fois des propriétés de A et des propriétés de B.
• Une instance de C pourra être vu comme un objet de type A et de type B.
A B
C
• Toutes les règles valables pour l’héritage simple sont valables pour l’héritage multiple.
• La déclaration de l’héritage multiple est de la forme : class C : public A, public B {…};
• Les constructeurs des super classes sont appelées dans l’ordre indiqué dans la déclaration de la sous-classe (ici celui de A puis celui de B).
• Si deux membres (données ou fonctions) appartenant respectivement à la classe A et à la classe B portent le même nom, la portée permettra d’en faire la différence dans la classe C (opérateur ::)
L’héritage multiple : généralitésL’héritage multiple : exemple
class A {public:int i;
};
class B {public:int i;
};
class C : public A, public B {public:void f();
};
void C::f() {i=5; // ambigu : erreur à la compilationA::i=5; // Ok, affectation de l’attribut i de la
// partie provenant de A.B::i=7; // Ok, affectation de l’attribut i de la
// partie provenant de B.}
Programmation objet en langage C++ 36Département Informatique de l'INSA- Jean-Marc Pierson
Héritage multiple et constructeurs
void main() {C objet_c;// appel des constructeurs B(), A() et C()
}
class A {public: A(int n=0) {}
};
class B {public:B(int n=0) {}
};
class C: public B, public A {public:
C(int i, int j):A(i),B(j) {} };
• Autre problème de l’héritage multiple : héritage multiple de la même classe.
• Par défaut, la classe D hérite deux fois de la classe A ce qui, dans la majorité des cas, n’a aucun intérêt : on parle alors d'héritage répété
Héritage multiple de la même classe :à éviter
B C
D
A
Héritage répété : exempleclass A {public:
virtual void m() {};};
class B : public A {};class C : public A {};
class D : public B, public C {};
À l'intérieur de la classe D, il y a héritage répété de la classe A; l'identificateur m qui en est hérité doit être explicitement qualifié B::m ou C::m . Dans D, il n'est pas possible de faire référence à m sans l'indicateur de portée ::
• Il est possible de limiter le nombre de présences d’une super classe dans une sous-classe en la déclarant virtualdans l’héritage : on parle d'héritage commun (à l'inverse de l'héritage répété par défaut)
Héritage commun
class A {…};
class B : public virtual A {…};
class C : public virtual A {…};
class D : public B, public C {…};
La classe D hérite une seule fois des membres de A.Attention : virtual est placé à l'héritage direct de A.
Programmation objet en langage C++ 37Département Informatique de l'INSA- Jean-Marc Pierson
class A {public:
virtual void m() {};};
class B : public virtual A {};class C : public virtual A {};
class D : public B, public C {};
À l'intérieur de la classe D, il y a héritage commun de la classe A; l'identificateur m est unique et peut être utilisé tel quel
Héritage commun : exemple Problème de l'héritage multipleclass A {public:
virtual void m() {};};
class B : public virtual A {};class C : public virtual A {
virtual void m() {}; // redéfinition de m};
class D : public B, public C {};
Dans la classe D, l'identificateur m peut-être soit celui de l'original (A::m), soit celui de C (C::m ). On peut utiliser l'identificateur m sans opérateur de portée : par défaut, c'est celui de C qui est utilisé
On n'hérite pas la terre de nos parents, nous l'empruntons à nos enfants
-- Léopold Sedar Senghor
"Programmation objet en C++"Plan
• introduction à la P . O . O, le C++ et le C• préprocesseur• types des données manipulables • classes/méthodes/fonctions• portée des noms/durée de vie des objets • fonctions ordinaires/bibliothèques• instructions• expressions/opérateurs• surcharge d'opérateurs • classes et fonctions génériques • héritage
• compléments : friend/conversions/exceptions• La librairie standard C++
Programmation objet en langage C++ 38Département Informatique de l'INSA- Jean-Marc Pierson
Fonctions et classes amies
• Pour permettre à une fonction d'accéder à des données privées d'une classe
• Principalement utilisé pour la surcharge d'opérateurs
• On peut aussi déclarer une classe entière comme étant amie : toutes ses méthodes pourront accéder à toutes les données
Utilisation des fonctions amiesclass Complex {public:Complex(int r=0, int i=0):re(r),im(i) {};
int re, im;};
Complex operator *(int k, Complex &c) {return Complex(k * c.re, k * c.im);
}
private: int re, im;
accès interdit !
Solution : fonctions amies
class Complex {public:Complex(int r=0, int i=0):re(r),im(i) {};friend Complex operator *(int k, Complex &c);private : int re, im;
};
Complex operator *(int k, Complex &c) {return Complex(k * c.re, k * c.im);
}
Classe amieclass Complex {
public:Complex(int r=0, int i=0):re(r),im(i) {};friend Affiche;
private : int re, im;
};
class Affiche {public:void print_complexe(Complex &c);
};
void Affiche::print_complexe(Complex &c) { cout << "Partie Réelle : " << c.re << endl;cout << "Partie Imaginaire : " << c.im << endl;
}
Toute la classe Affiche (et donc toutes ses méthodes) a un accès à la classe Complex
Programmation objet en langage C++ 39Département Informatique de l'INSA- Jean-Marc Pierson
Méthode amieclass Complex {public:
Complex(int r=0, int i=0):re(r),im(i) {};friend Affiche::print_complexe(Complex &c);
private : int re, im;
};
Seule la méthode print_complexe a un accès à la classe Complex
Compléments sur l'amitié• L'amitié n'est pas symétrique : si une classe A est amie d'une
classe B, alors B n'est pas forcément amie de A• L'amitié n'est pas transitive : les amis des amis ne sont pas des
amis ; si une classe A est amie d'une classe B, elle-même amie d'une classe C, alors A n'est pas amie de la classe C par défaut(mais on peut bien sûr la déclarer amie explicitement si on désire)
• L'amitié n'est pas héritée : si une classe A est amie d'une classe B et que la classe C est une classe fille de la classe B,alors A n'est pas amie de la classe C par défaut (mais on peut bien sûr la déclarer amie explicitement si on désire); par contre si D hérite de A, alors D est amie de B
• remarques valables pour les fonctions aussi : une fonction amie d'une classe A amie d'une classe B n'est pas amie de la classe B, ni des classes dérivées de A
Conversions de type implicites• automatiquement effectuées par le compilateur pour :
• l'évaluation d'une expression : 3/4.3 // l'entier 3 est converti en float• le passage de paramètres à une fonction :
void f(float a) { cout << a; };void main() {
int i = 4; f(i); // l'entier 4 est converti en float
}• l'affectation : int i; char c = i; // quelle valeur pour c ?
• entre types primitifs : – booléen -> entier (false/true -> 0/1)– entier ou pointeur -> booléen (nul/non nul -> false/true)– entier -> entier de taille supérieure (char -> short -> int-> long)– entier non signés -> entiers signés– enum -> int– entier -> float -> double
• entre objets de même type : pointeurs d'objets de classes liées par héritage
Les conversions de type explicites (à éviter)
• Conversion contrôlée par le compilateur : static_cast <type> (expression)
• Conversion contrôlée à l'exécution :dynamic_cast <type>(expression)
• Conversion sans contrôle :reinterpret_cast <type>(expression)
• Conversion "à la C"(type) expression : exemple : (float)3
Programmation objet en langage C++ 40Département Informatique de l'INSA- Jean-Marc Pierson
Conversions : d'une Classe vers un type T
• par la définition d'un opérateur unaire "operator T" qui renvoie une valeur de type T (type primitif ou une classe)class A { public :
A() { m_a = 10; }operator int (); // conversion d'un A en int
private: int m_a;};
void main() { A objet_A; int b = objet_A + 3;
}
A::operator int() { return m_a;}
Conversions : d'un type T vers une Classe• par la définition d'un constructeur qui convertit un objet de
type T (primitif ou classe) en objet de la classe A
class A { public :
A() { m_a = 10; }A(int &valeur) { m_a = valeur; }
private: int m_a;};
void main() { int b = 3;A objet_A = (A)b;A objet_A2 = b;A objet_A3 = A(b);A objet_A4(b);
}
Attention aux conversions implicites !class B { public :
void uneMethodeDeB(A objetA);
void main() { int c = 3;B oB;
oB.uneMethodeDeB( c );}
Ici, c est converti en instance de la classe A avant d'être passé
en paramètre à uneMethodeDeB()...
Moralité : éviter les constructeurs à un seul paramètre et ceux où seul le premier est obligatoireclass A { public :
A(int &valeur1, int &valeur2 = 1) { m_a = valeur + valeur2; }};
Conversions explicites définies par l'utilisateur
• si on ne veut pas que le constructeur précédent réalise une conversion implicite, il faut faire précéder la déclaration de explicit
class A { public :
A() { m_a = 10; }explicit A(int &valeur) { m_a = valeur; }
private: int m_a;};
void main() { int b = 3;A objet_A = (A)b;A objet_A2 = b; A objet_A3 = A(b);A objet_A4(b);
}
INTERDIT: la conversion doit être
explicite
Programmation objet en langage C++ 41Département Informatique de l'INSA- Jean-Marc Pierson
Les exceptions• Le programme idéal est un programme sans erreur !• Le compilateur est le premier niveau de contrôle des erreurs
dites de syntaxe, de type, voire de sémantique.• Le deuxième niveau de contrôle fait intervenir la notion
d’exception.• Lors du développement, on ne peut jamais savoir ce que
l’utilisateur de la classe ou du programme va faire :float inverse(float a) {
return 1/a; // si a = 0 ?}
Exceptions : principe• Si une fonction rencontre un problème qu'elle ne peut
pas traiter, elle lance ("throw") une exception en espérant que son appelant pourra le traiter en interceptant("catch") cette exception .
• Syntaxe :try{ // bloc pouvant "lancer" une exception par
throw exprException ;}catch (TypeException){ //gestionnaire des exceptions de type TypeException}
• Les exceptions permettent de séparer le bloc d'instructions de la gestion des erreurs pouvant survenir dans un bloc.
try {// Code pouvant lever des exceptions
}catch (type [[&]variable]){
// Gestion de l'exception}
Les exceptions
Le mot clé try indique que le code du bloc peut soulever des exceptions et que si c’est le cas alors il y aura exécution d’un bloc marqué par le mot clé catch.
Un bloc catch prend en paramètre un type quelconque (classe, par exemple). On peut en définissant plusieurs blocs catch prenant différents types d’exception réalise un traitementdifférent selon l’exception soulevée.
Exemple d'exceptions
#include <exception>
try {char *ptr = new char[1000000000];// ... suite en cas de succès de new (improbable ...)
}catch ( bad_alloc ) {
// en cas d'échec d'allocation mémoire par new// une exception bad_alloc est lancée par new
// traitement de l'erreur d'allocation}
Bibliothèque des exceptions prédéfinies
Programmation objet en langage C++ 42Département Informatique de l'INSA- Jean-Marc Pierson
Spécification d'exceptions (1/2)• L'appel à une méthode pouvant lever une exception doit :
– soit être contenu dans un bloc try/catchchar * alloue(int size){char *ptr;try {
char *ptr = new char[size];}catch (bad_alloc) {
cout << "Allocation impossible";
}return ptr;
}
Spécification d'exceptions (2/2)– soit être situé dans une méthode propageant (throw) cette
classe d'exception. La méthode ne traite pas l’exception mais laisse la méthode appelante traiter l’exception
char * alloue(int size) throw (bad_alloc) {char *ptr = new char[size];return ptr;
}
• de bloc en bloc : remontée dans l'appel des méthodes jusqu'à ce qu'un bloc catch acceptant cette exception soit trouvé.
• Si aucun bloc catch n'est trouvé, la fonction spéciale terminate() est appelée et le programme s'arrête. Il est possible de changer cette fonction à l'aide de la fonction set_terminate(maFonctionDeFin);
• Un bloc catch(...) intercepte toutes les exceptions.• On peut re-propager une exception depuis un bloc catch
avec throw;:l'exception est alors relancée au bloc englobant
Propagation des exceptionsNon propagation des exceptions
• On peut signifier qu'une fonction ne propage jamais une exception aux fonctions appelantes :
•void f() throw()
indique que la fonction f ne propage aucune exception.
• Par défaut, une méthode peut propager toutes les exceptions.
Programmation objet en langage C++ 43Département Informatique de l'INSA- Jean-Marc Pierson
• Les programmes peuvent aussi gérer des exceptions qui seront ensuite traiter par la méthode vue précédemment.
• La levée d’une exception passe par la création d’une instance d’une classe ou d'un type et l’utilisation du mot clé throw.
if(t == null)throw NullPointerException();
Throw : lancer des exceptionsclass Essai { public :
class Erreur { };void f1() { throw Erreur(); }
};
void main() {try {
Essai e1;e1.f1();
}catch ( Essai::Erreur ) {
cout << "interception de Erreur" << endl;}
}
Exemple d'exception
class Essai { public :
class Erreur { public: string getMessage()
{ return "Errare humanum est"; }};void f1() { throw Erreur(); }
};
void main() {try {
Essai e1;e1.f1();
}catch ( Essai::Erreur & e) {
cout << e.getMessage() << endl;}
}
Exemple d'exception
• Si une exception est levée dans une fonction ou méthode ne propageant pas l'exception alors la fonction unexcepted() est appelée et le programme est arrêté (par défaut cette fonction fait appel à terminate() )
• On peut définir sa propre fonction unexpected() par un appel à la fonction set_unexpected(maFonctionInattendue);
Exceptions inattendue
Programmation objet en langage C++ 44Département Informatique de l'INSA- Jean-Marc Pierson
Exemple d'exception inattendue#include <iostream.h>
void my_unexpected() {cout << "my_unexpected" << endl;exit(1);
}class Erreur {};class Toto {};class Essai {
public:void f1() throw (Erreur);
};
void Essai::f1() throw (Erreur) {
throw Toto();}
void main() {set_unexpected(& my_unexpected);try {
Essai e1;e1.f1();
}catch ( Erreur ) {// gère l'Erreur : jamais appelé ici ! }
}
Hiérarchie d'exception et ordre d'interception
• Lorsque plusieurs gestionnaires d'exceptions sont précisés, on les essaie dans l'ordre d'apparition dans le code
• Suite au lancement d'une exception de classe T, le gestionnaire activé est celui qui intercepte : – le type T– soit une classe dont T est un descendant par héritage
public– un type pointeur dans lequel T (supposé être un
pointeur) peut être converti
Exemple de hiérarchie d'exceptionsclass ErreurMath {};class Depassement : public ErreurMath {};class DivisionParZero : public ErreurMath {};// ...try { // du code sensé lever une exception mathématique}catch (DivisionParZero) {
// gère l'exception DivisionParZero (et toutes ses descendantes)}catch (ErreurMath) {
// gère toutes les autres exceptions sous classe de ErreurMath}
Programmation objet en langage C++ 45Département Informatique de l'INSA- Jean-Marc Pierson
Constructeurs et exceptions
• Les constructeurs ne renvoient pas de valeurs : les exceptions peuvent être un moyen de signifier des erreurs à la construction d'un objet : l'objet n'est alors pas construit, et il n'y a pas appel au destructeur !
Exemple de Constructeurs avec Exceptionclass A {
public:A(string & mess) throw (int) {
cout << "constructeur" << endl;tableau = new char[10];throw 2;
pointeur = new int; // jamais exécuté}
~A() { cout << "destructeur jamais appelé !" << endl; }private:
char [] tableau; int *pointeur;};void main() {
try { A a = new A("coucou"); }catch (...) { cout << "Erreur construction" << endl;}
}L'opérateur delete est appelé sur l'objet, mais pas le destructeur
Exemple de Constructeurs avec Exceptionclass A {
public:A(string & mess) throw (int)
try {message = NULL; pointeur = NULL;cout << "constructeur" << endl;tableau = new char[10];throw 2;
pointeur = new int; // jamais exécuté}catch (int) {
delete [] tableau; delete pointeur;
}
~A() { cout << "destructeur" << endl; }private: char [] tableau; int *pointeur;
};
Combinaison Constructeurs/Héritage/Exceptionclass B : public A, public C {
public:B(string & mess) throw (int)
try : A(mess), C(mess) {cout << "constructeur" << endl;throw 2;
}catch (int) {
message = mess;}
~A() { cout << "destructeur" << endl; }private: string message;
};
Les appels aux constructeurs de A et C peuvent lancer des exceptions : ces exceptions, même si elles sont traitées dans A ou C sont renvoyées vers B (contrairement à d'habitude); aucun objet n'est créé
Programmation objet en langage C++ 46Département Informatique de l'INSA- Jean-Marc Pierson
Compléments sur les exceptions
• La clause throw n'intervient pas dans la signature d'une méthode (pour la surcharge et la redéfinition)
• pour les méthodes const, on la met après le const
• pour les méthodes virtuelles pures (=0), on la met avant le =0
exemple : void f() const throw (int) = 0;
Les flux d’E/S• Un flux, appelé stream en C++, est un périphérique logique
qui produit ou consomme des informations.• Un stream représente un flot de données entre une source
(producteur) et une cible (consommateur).• Pour utiliser un stream, il faut inclure le ou les fichiers
suivants :– iostream : flux standards (cout, cin, cerr…)– fstream : fichier– strstream : chaîne de caractères vu comme un flux– iomanip : pour utiliser les manipulateurs
• Il existe 4 flux standards :– cin : saisie clavier– cout : sortie écran– cerr : sortie écran pour l’affichage des erreurs– clog : sortie bufférisée écran
• Ces 4 flux peuvent être redirigés (cerr vers un fichier, par exemple).
Les flux standards• Toutes les classes gérant des flux possède un objet de la
classe streambuf qui est une représentation du bufferdans lequel on lit ou écrit : on le récupère avec la méthode rdbuf()
• Toutes les entrées-sorties sont bufferisées : on peut changer le buffer (et donc sa taille) avec la méthode pubsetbuf(char *newbuf, int taille)
• La classe ios ancêtre des toutes les classes de type stream gère l’accès au buffer : c'est l'équivalent de la classe basic_ios<char>
• De même, par exemple, la classe istream est la classe basic_istream<char>
La hiérarchie des classes
Programmation objet en langage C++ 47Département Informatique de l'INSA- Jean-Marc Pierson
La hiérarchie des classes d'entrée/sorties
• A chaque flux est associé un vecteur de bits formant le statut d’erreur :– eofbit : activé si la fin du fichier a été atteinte c-à-d si le flux
n’a plus aucun caractère disponible– failbit : activé si la dernière opération d’E/S a échoué– badbit : activé si la dernière opération d’E/S est invalide– hardfail : activé si le flux est dans un état d’erreur
irrécupérable
• L’accès aux bits d’erreur se fait par l’intermédiaire de 4 fonctions membres : eof(), bad(), fail() etgood().
• La fonction good() retourne vrai (1) s’il y a aucune erreur.
L'état des flux
Exemple d'utilisationint x = 1;char ch1;do {
cout << "Entrer un nombre :" << endl;cin >> x;
if (cin.fail()) { cin.clear(); // on efface les bits de statuscin >> ch1;cout << "Valeur incorrect entrée";
}else cout << "Le nombre lu est " << x <<
endl;} while (x != 0);
• L’opérateur () est redéfini de manière à ce que si fl désigne un flux alors (fl) prenne une valeur non nulle si aucun des bits d’erreur n’est activé et prenne une valeur nulle dans le cas contraire.
if (fl) … <==> if (!fl.good()) …
• L’opérateur ! est redéfini de manière à ce que si fl désigne un flux alors !fl prenne une valeur nulle si un des bits d’erreur est activé et prenne une valeur non nulle dans le cas contraire.
Fonctions et opérateurs sur flux
Programmation objet en langage C++ 48Département Informatique de l'INSA- Jean-Marc Pierson
• L’écriture dans un stream s’effectue à l’aide de l’opérateur << :
ostream& operator<<(…);Le type de retour permet d’utiliser l’opérateur << en cascade.
((cout << "hello") << "world");
• La lecture dans un stream s’effectue à l’aide de l’opérateur >> :
istream& operator>>(…);
• Les opérateurs << et >> sont définis pour tous les types primitifs.
Les opérateurs << et >>
• Si vous désirez que les instances de vos classes puisse s’afficher à l’écran ou s’enregistrer dans un fichier, il faut surcharger l’opérateur <<.
• Il ne peut être écrit qu’en dehors d’une classe stream (on ne peut pas modifier le code d’une classe des librairies standards !) et évidemment en dehors de vos classes (car le premier opérande est un stream !).
• Il faut donc définir l’opérateur << à l’extérieur de vos classes et en général ami de vos classes afin d’avoir accès à leurs membres : si l'opérateur << n'est pas ami, il ne peut avoir accès aux donnéesprivées de A
Redéfinition de << (ou >>)
Exemple de redéfinition de <<class A {
private :int m_a;
public :A(int p_a):m_a(p_a) { }
friend ostream& operator<<(ostream &, A const &);};
ostream& operator<<(ostream& o,A const & a){
o << a.m_a;return o;
}
void main(){
A a(9);cout << A << endl;
}
• En plus de l'opérateur <<, la classe ostream contient les méthodes suivantes :– ostream & put(char c); : insère un caractère dans le flux.– ostream & write(const char *, int n); : insère n caractères
dans le flux.– streampos tellp(); : retourne la position courante dans le flux.– ostream & seekp(streampos n); : se positionne à n octet(s) par
rapport au début du flux. Les positions dans un flux commencent à 0 et le type streampos correspond à la position d'un caractère dans le flux.
– ostream & seekp(streamoff dep, seek_dir dir); : se positionne à dep octet(s) par rapport :
• au début du flot : dir = beg • à la position courante : dir = cur • à la fin du flot : dir = end (et dep est négatif!)
– ostream & flush(); : vide les tampons du flux.
Méthode des flux de sortie
Programmation objet en langage C++ 49Département Informatique de l'INSA- Jean-Marc Pierson
Exemple d'utilisationvoid main()
{
cout << "Quelques essais sur les flux" << endl ;
// Rouge : suite de char faisant passer un terminal ANSI à // la couleur rouge pour l'écritureconst char Rouge[] = { 033, '[' , '3', '1', 'm' };cout.write( Rouge, sizeof(Rouge));cout << "Ecriture en rouge" << endl;
const char Reset[] = {033, '[', 'm', 017};cout.write( Reset, sizeof(Reset));cout << "Retour à la normale" << endl;
}
Exécution :Quelques essais sur les flux
Ecriture en rougeRetour à la normale
• En plus de l'opérateur >>, la classe istream contient les méthodes suivantes :– int get(); : retourne la valeur du caractère lu (ou EOF si fin)– istream & get(char &c); : extrait le premier caractère du flux
et le place dans c. – int peek(); : lecture non destructrice du caractère suivant– istream & get(char *ch, int n, char delim='\n'); :
extrait n -1 caractères du flux et les placent à partir de l'adresse ch. La lecture s'arrête avant le délimiteur delim
– istream & getline(char *ch, int n, char delim='\n');: comme la méthode précédente sauf que le délimiteur est extraitdu flux mais n'est pas recopié dans le tampon.
Méthode des flux d'entrée
– istream & read(char *ch, int n); : extrait un bloc d' au plus n octets du flux et les place à l'adresse ch. Le nombre d'octetseffectivement lus peut être obtenu par la méthode gcount().
– int gcount(); : retourne le nombre de caractères non formatés extraits lors de la dernière lecture
– streampos tellg(); : retourne la position courante dans le flux.– istream & seekg(streampos n); : se positionne à n octet(s) par
rapport au début du flux. Les positions dans un flot commencent à 0 et le type streampos correspond à la position d'un caractère dans le flux.
– istream & seekg(streamoff dep, seek_dir dir); : se positionne à dep octet(s) par rapport au début du flux, à la position courante ou à la fin du flux.
Méthode des flux d'entrée (suite) • La manipulation des fichiers est rendu possible grâce à deux classes : ifstream et ofstream.
• Définies dans <fstream>• L'ouverture d'un flux de type fichier est réalisé par le
constructeur.ifstream f("toto.txt");ofstream f("toto.txt", ios::app |
ios::nocreate);
• ou alors par l'appel à la méthode open( ... )fstream f3;
f3.open("toto.txt", ios::in | ios::out);
• fermeture par la méthode close()
Les fichiers : des streams particuliers
Programmation objet en langage C++ 50Département Informatique de l'INSA- Jean-Marc Pierson
MODE
D'OUVERTURE
Exemple d'utilisation
void main()
{
cout << "Quelques essais sur les flux" << endl ;
// on se positionne à la fin du fichierifstream f("essai.txt", ios::ate);
cout << "Taille du fichier en octets = ";
// on regarde où on est
cout << f.tellg() << endl;
}
Les chaînes de caractères vues comme des flux
• On peut associer un flux de caractère à une chaîne : les opérations définies sur les stream deviennent valables
• C'est la classe strstream (ou sstream)• Définies dans <strstream> (ou
<sstream>)• Un buffer particulier est utilisé : stringbuf
Exemple d'utilisation// création d'un objet strstream en lecture/écriture par défautstrstream inout;
// écriture de 2 lignes sur ce fluxinout << "C'est l'histoire d'un homme" << endl
<< "This is the story of a man." << endl;char line [80];
// extract the first lineinout.getline (line, sizeof line);
// output the first line to stdoutcout << "Français: " << line << endl;
// extract the second lineinout.getline (line, sizeof line);cout << "English:" << line << endl;
// output the contents of the stream object to stdoutcout << endl << inout.str () << endl;
Programmation objet en langage C++ 51Département Informatique de l'INSA- Jean-Marc Pierson
• Il existe au niveau de la classe ios plusieurs champs utilisés pour le formatage des entrées-sorties :– precision : précision pour la sortie des réels (float ou double)– width : longueur du champ de sortie– fill : caractère de remplissage des champs de sortie lorsque le
champ est plus grand que l’information– flags : définition du format
• Ces différents champs sont accessibles via des fonctions membres (setf, unsetf, width, precision et fill).
• Les deux premières fonctions permettent de préciser les flags de formatage.
Formatage Flags
de
formatage
Formatage
formatage
Programmation objet en langage C++ 52Département Informatique de l'INSA- Jean-Marc Pierson
Formatage : les fonctions de manipulation
Formatage : exempledouble f = 0.123456789;cout.fill('*');cout.precision(3); // 6 par défautcout.setf(ios::showpos | ios::scientific | ios::right);cout << "Valeur de f : |" ;cout.width(20); // le prochain champ affiché sera sur 20 caractèrescout << f << "|" << endl;cout.unsetf(ios::right);cout.setf(ios::left | ios::fixed);cout << "Valeur de f : |";cout.width(20);cout << f << "|" << endl;
Exécution :Valeur de f : |**********+1.234e-01|
Valeur de f : |+0.123**************|
Formatage : exemple n°2ifstream fic;
ofstream fic2;
char c;
fic.setf(ios::skipws);
fic.open("test.txt");
fic2.setf(ios::skipws);
fic2.open("test2.txt");
while (!fic.eof())
{
fic >> c;
fic2.put(c);
}
fic.close();
fic2.close();
En sortie,le fichier test2.txt est le fichier test.txt, sans les blancs (est blanc un caractère pour qui la fonction isspace() renvoie vrai)
Les manipulateurs
• Les manipulateurs sont des fonctions qui agissent sur les formats d’entrées/sorties.
• Evitent de se servir de setf et unsetf• Elles nécessitent l’inclusion de iomanip• Le plus connu est endl (retour chariot + retour à la
ligne) mais il en existe d’autres.• Ne s'appliquent que sur l'opération qui suit (sauf
certaines qui s'appliquent globalement)
Programmation objet en langage C++ 53Département Informatique de l'INSA- Jean-Marc Pierson
Les manipulateurs sans arguments
Il faut ajouter :* ws (ignorer les espaces en entrée)* dec,hex,oct* flush* endl, ends
cout << hex << 17 << endl;
Les manipulateurs sans arguments (suite)
• Comment écrire un manipulateur sans argument ?1) surcharge de l’opérateur << comme suit :ostream& operator<< (ostream&,
ostream& (*pf)(ostream&));
2) écrire une fonction prenant comme paramètre un streamet retournant une référence sur un stream.
Ses propres manipulateurs ?
ostream& toto(ostream& o){
o << "MANIPULATEUR";return o;
}
cout << "abc : " << toto <<endl;
Exécution :abc : MANIPULATEUR
Les manipulateurs avec arguments
cout << "|";cout << setw(10) << "bonjour";cout << "|";
Exécution :|bonjour |
Programmation objet en langage C++ 54Département Informatique de l'INSA- Jean-Marc Pierson
• Comment écrire un manipulateur avec arguments ?1) écrire une fonction prenant en paramètre un stream et
les arguments souhaité, et retournant une référence sur un stream.
ostream& manip(ostream& o,int i) {o << "MANIPULATEUR AVEC PARAMETRE = " << i;return o;
}
2) redéfinition de l’opérateur << (ou >>)ostream& operator<<(ostream& o,
NewManipulator m){ return m.pf(o,m.i); }
Ses propres manipulateurs ?3) écrire la classe NewManipulatortypedef ostream& (*t_pf)(ostream&,int);
// pointeur vers une fonction qui admet un stream et un entier en // paramètres et qui retourne une référence sur stream
class NewManipulator {int i;t_pf pf;public:
NewManipulator(t_pf p_pf, int x):pf(p_pf),i(x) { }
};
4) écrire une fonction (ce sera le manipulateur) qui prend un entier en paramètre et qui renvoie un NewManipulateurNewManipulator appelManipulateur(int i) {
return NewManipulator(manip,i); }
Les manipulateurs avec arguments
Manipulateurs avec arguments (fin)
• Utilisation : cout << appelManipulateur(3) << endl;
• Exécution :MANIPULATEUR AVEC PARAMETRE = 3
Pièges du C / C++
• Pièges syntaxiques– une erreur de syntaxe dans l'écriture d'une
expression C/C++ : la plupart sont détectées à la compilation
• Pièges sémantiques– une méconnaissance du langage entraîne des
erreurs difficilement détectables : le compilateur compile sans problème, mais le comportement n'est pas celui attendu
• Performances médiocres ...
Programmation objet en langage C++ 55Département Informatique de l'INSA- Jean-Marc Pierson
• if ( 0 < a < 5)// expression booléenne toujours vraie
• if (a=b)// vraie si b est différent de 0
• int numbers[] = {
001, // on aligne les nombres. Mais ...
010, // 8 pas 10, expression évaluée en octal !
014 }; // 12, pas 14
Quelques erreurs communes en C• int thisIsNuts[4], i; for ( i = 0; i < 10; ++i ) { thisIsNuts[ i ] = 0; }
• int i = 1;
printf("%d, %d, %d\n", i++, i++, i * i);
• int i = 1;
i/++i
• appelDeFonction(pointeur->membre, pointeur=&buffer);
• char *f() { char result[80]; sprintf(result,"anything will do"); return(result); }
int g() { char *p; p = f(); cout << "f() returns:" << p << endl; }
• maFonction,(arg1,arg2,arg3);
• switch (a) {
int var = 1; // jamais exécutécase A: ...
case B: ...
}
• switch (a) {
case A: ...
case B: ...
defaut : // jamais exécuté}
Programmation objet en langage C++ 56Département Informatique de l'INSA- Jean-Marc Pierson
• int maFonction (a) {
if (a) return(1);
}
• #define maximum(a,b) (a>b?a:b)
maximum(i++, j); // s'évalue en i++>j?i++:j
maximum(i=1,j=2); // s'évalue en i=1>j=2?i=1:j=2
Quelques erreurs en C++• int main() {
string a("Hello");string b(); // constructeur par défaut ? : non !...return 0;
}
• int n;while (!cin.eof()) {
cin >> n; // et si on entre abcd ?}
template<typename T> class Array { public:
Array(int size); T& operator[](int); Array<T>& operator=(const Array<T>&);
};
int main() {
Array<double> a(10);
a[0] = 0; a[1] = 1; a[2] = 4;
a[3] = 9; a[4] = 16; a = 36;
a = 36; a[7] = 49; a[8] = 64;
}
class Point {
public:
Point(double x = 0, double y = 0);
private:
double _x, _y;
};
int main() {
double a, r, x, y;
Point p = (x + r * cos(a), y + r * sin(a));
return 0;
}
Programmation objet en langage C++ 57Département Informatique de l'INSA- Jean-Marc Pierson
template<typename T> class Array { public: explicit Array(int size); private:
T* _data; int _size;
}; template<typename T> Array<T>::Array(intsize) : _size(size), _data(new T(size)) {}
int main() { Array<double> a(10); a[1] = 64; // le programme plante: pourquoi ?
}
template<typename T> class Array { public: explicit Array(int size); private:
T* _data; int _capacity;int _size;
}; template<typename T> Array<T>::Array(intsize) : _size(size),
_capacity(_size+10),_data(new T[_capacity]) {}
int main() { Array<double> a(100); // le programme plante: pourquoi ?
}
class Chaine {public :
Chaine(); // constructeur par défautChaine( const char * ch); // copie de ch dans bufferoperator = (Chaine & c); // copie de c.ch dans buffer
private : char * buffer;}class Name {
public: Name (const char * t) { name = t; }private : Chaine name;
}
int main() {Name a = "Joe";
}
// combien d'appel de création, de copie et de destruction ?1 - appel de Name::Name("Joe");2 - construction de Name::name, par défaut : 1 new3 - Chaine temporaire créée à partir de "Joe" : 1 new + 1 copie4 - Appel à l'opérateur = de la classe Chaine : 1 copie5 - le 4) entraîne la destruction de Name::name créé à l'étape 2,
puis un nouveau new puis la copie6 - le temporaire créé en 3) est détruit
Total : 3 new, 3 copies, 2 delete
class Chaine {public :
Chaine(); // constructeur par défautChaine( const char * ch); // copie de ch dans bufferoperator = (Chaine & c); // copie de c.ch dans buffer
private : char * buffer;}class Name {public: Name (const char * t):name(t); }private : Chaine name;
}int main() {Name a = "Joe";
}
// combien d'appel de création, de copie et de destruction ?1 - appel de Name::Name("Joe");2 - appel au constructeur de Chaine qui
correspond : 1 new + 1 copie
Programmation objet en langage C++ 58Département Informatique de l'INSA- Jean-Marc Pierson
class Shape {
public:
Shape() { reset(); }
private:
virtual void reset();
Color _color;
};
void Shape::reset() {
_color = BLACK;
}
class Point : public Shape {
public:
// pas de constructeur
virtual void reset();
private:
double _x, _y;
};
void Point::reset() {
Shape::reset();
_x = 0; _y = 0;
}
int main() {
Point p; // _color, _x, _y = ?
}
class Shape { //classe
// abstraite
public:
Shape() { init(); }
private:
void init() { reset(); }
virtual void reset()=0;
Color _color;
};
class Point : public Shape {
public:
// pas de constructeur
virtual void reset();
private:
double _x, _y;
};
void Point::reset() {
_x = 0; _y = 0;
}
int main() {
Point p; // le programme plante. Pourquoi ?
}
class A {public:
virtual void f(string s = "Base") {cout << "Classe de Base" << s << endl;
}}
class B : A {public:
virtual void f(string s = "Derived") {cout << "Classe dérivée : " << s << endl;
}}
int main() {B *b = new B;b->f(); // affiche : Classe dérivée : DerivedA *a = b;a->f(); // affiche : Classe dérivée : Base
}
class Employee {public:Employee(string name);virtual void print();
private:string _name;
};
class Mngr : public Employee {public:Mngr( string name,
string dept);virtual void print();
private:string _dept;
};
int main() { Employee* staff[10];staff[0] = new Employee("Harry Hacker");staff[1] = new Mngr("Joe Smith", "Sales");for (int i = 0; i < 10; i++) staff[i]->print();for (int i = 0; i < 10; i++) delete staff[i];
// de la mémoire n'est pas libérée : où ?}
Programmation objet en langage C++ 59Département Informatique de l'INSA- Jean-Marc Pierson
class Employee {public:Employee(string name);virtual ~Employee();
private:string _name;
};Employee::~Employee {
delete _name;}
class Mngr : public Employee {public:Mngr(string n, string sn):Employee(n), _secretary(new Employee(sn))
{};~Mngr();
private:Employee* _secretary;
};Mngr::~Mngr() {
delete _secretary;}
int main() {
Mngr m1 = Mngr("Sally Smith", "Joe Barnes");
Mngr m2 = m1;
} // problème à la destruction des deux Mngr
Quelques liens
• C Traps and Pitfalls, A. Koenig (http://www.programmersheaven.com/zone3/cat36/391.htm)
• http://www.michaelmoser.org/cppitfalls.htm• http://www.horstmann.com/cpp/pitfalls.html
While many languages let you shoot yourselfin the foot, C gives you a shotgun and lets you shoot yourself in the head.
-- Matt Spong (GNU C/C++ developper)
C et C++• Différences syntaxiques : des mêmes choses
s'écrivent différemment : (ex: les commentaires, le typedef devant les structures)
• Différences conceptuels : – C n'est pas un langage objet : pas de classes,
seulement des fonctions; pas de redéfinition de méthodes, pas de surcharge d'opérateur
– Pas de références : passage des paramètres aux fonctions par valeur ou par adresse
– Typage moins fort qu'en C++
Programmation objet en langage C++ 60Département Informatique de l'INSA- Jean-Marc Pierson
Name mangling en C++• Pour la production des fichiers objets, à la
compilation, transformation des noms de fonctions pour faire apparaître la signature dans le nom– exemple : long abs(long arg);
sera transformé (par exemple) en : abs_long• Deux signatures -> deux noms internes différents• Rappel : signature = nom+arguments (pas retour)
Coexistence C / C++
• En C, ce mécanisme n'est pas utile : les fichiers objets produits pour le C (et les bibliothèques qui les contiennent) contiennent seulement le symbole du nom de la fonction (abs dans l'exemple)
• Il faut indiquer au compilateur C++ que certaines fonctions sont "C" alors que d'autres sont "C++", afin qu'il retrouve les symboles internes correspondants : le mot clé extern
#include <stdio.h>#include <toto.h>void f(void) {
printf("Hello de f");}
Fichier toto.c
Fichier toto.o
gcc -c toto.c
extern "C" void f(void);
Fichier toto.h
#include <iostream>#include <titi.h>void g(void) {
cout<< "Hello de g" <<endl;}
Fichier titi.cpp
Fichier titi.og++ -c titi.cpp
extern "C++" void g(void);
Fichier titi.h
#include <toto.h>#include <titi.h>void main(void) {
f();g();
}
g++ -c main.cpp
Fichier main.cpp
Fichier main.o
Liaison : (production de l'exécutable)g++ -o affiche main.o toto.o titi.o
Coexistence avec extern
• Dans l'exemple, si on n'avait pas mis extern"C" dans toto.h, alors le compilateur C++ aurait créé un symbole interne "à la C++", au lieu de le créer "à la C" : à la liaison, il n'aurait pas été reconnu !
• Par défaut (si on ne met pas extern), le compilateur C++ ajoute extern "C++"
Programmation objet en langage C++ 61Département Informatique de l'INSA- Jean-Marc Pierson
Compilation conditionnelle• Ajout de :#ifdef __cplusplusextern "C" void f( void );
#elsevoid f( void );
#endif
ou alors #ifdef __cplusplus
extern "C" { #endif
void f(void);void f2(int, int);...
#ifdef __cplusplus}
#endif
Déclaration des fonctions en C et C++
int f( );
• En C, cette déclaration implique que la fonction f accepte un nombre quelconque d'arguments, de n'importe quels types
• En C++, cette déclaration implique que la fonction f n'a pas d'arguments : elle est équivalente à int f(void);
Déclaration implicite ?
int f( ) {g(); // fonction non déclarée avant
}
• En C, cette déclaration est légale : elle implique une déclaration implicite de la fonction g comme suit : extern int g();
• En C++, cette déclaration est illégale : il aurait du y avoir une déclaration de la fonction g avant
Liaison interne/externeconst int i = 10;
• En C, cette déclaration entraîne que la variable i est visible depuis tous les fichiers objets : portée globale, la liaison est externe par défaut; pour la rendre locale, on rajoute le mot clé static :static const int i = 10;
• En C++, elle n'est visible que dans le fichier objet où elle est déclarée (liaison interne); pour la rendre globale, on rajoute le mot clé extern :extern const int i = 10;
Programmation objet en langage C++ 62Département Informatique de l'INSA- Jean-Marc Pierson
Utilisation d'une variable globale
extern const int i = 10;Fichier toto.c
#include <iostream>
extern const int i; // indique que la constante i a été déclarée ailleurs
void main( void ) {cout << i = " << i << endl;
}
Fichier main.cpp
Initialisation des static
static int i = 10 + 20;
• en C, on ne peut initialiser qu'avec des constantes
static int i = 10 + f();
• en C++, on peut initialiser avec des fonctions
Gestion de la mémoire
• En C : – void * malloc( size_t );– void free ( void * );
• En C++ : – new ou new[ int ]– delete ou delete []
#include <malloc.h>
void main( void ) {int * buffer;buffer = malloc(10*sizeof(int));free ( buffer);
}
void main( void ) {int * buffer;buffer = new int[10]; delete [] buffer;
}
Meilleur contrôle des types, meilleure extensibilité et efficacité
Transtypage void *
void main( void ) {int * buffer;buffer = malloc(10*sizeof(int));
• ok en C, pas en C++ : la fonction malloc() renvoie un void *, pas un int *
• pour que ce soit valide (en C et C++), il aurait fallu écrire : buffer = (int *) malloc(10*sizeof(int));
Programmation objet en langage C++ 63Département Informatique de l'INSA- Jean-Marc Pierson
Conversion de type en C• Il n'existe que l'opérateur (type) :
– (float) 3 transforme l'entier 3 en 3.0
• Impossible d'utiliser float(3) • Pas de conversion avec static_cast, const_cast, ...• En C, les littéraux (ex: 'a') sont de type int : sizeof('a') == sizeof(int) == 4
• En C++, les littéraux (ex: 'a') sont de type char : sizeof('a') == sizeof(char) == 1
• Mais en C++ comme en C, ils sont converti en int lorsqu'ils apparaissent dans une expression
Gestion des fichiers en C• En C, les flux sont de types FILE *• Les flux standards sont stdout, stderr, stdin.• Les flux se manipulent avec les fonctions C fopen(),
fclose(), fprintf(), ...{char *s = "toto";int i = 3;FILE * fic = fopen ("toto.txt", "w");fprintf(fic, "%s %d", s, i);fclose(fic);
}
• La fonction printf(...) est en fait un fprintf(stdout, ...)
Format d'affichage en C
• "%d" : la valeur est interprétée comme un entier, affiché en décimal
• "%5d" : un champ de 5 caractères est réservé pour afficher l'entier : justification à droite
• "%-5d" : pareil sauf : justification à gauche • "%x" : la valeur est interprétée comme un entier, affiché en
haxadécimal• "%u" : la valeur est interprétée comme un entier non signé
(unsigned)• "%s" : la valeur est interprétée comme une chaîne de caractère
(tableau de caractère terminé par \0)• "%f" : la valeur est interprétée comme un float• "%5.2f" : la valeur est interprétée comme un float : affichage
de 5 chiffres significatifs, dont 2 après la virgule
Gestion des fichiers{char *s = "toto";int i = 3;printf(fic, "%s %s\n" s, i);fclose(fic);
}
• Ce programme plantera probablement : essai d'affichage d'une chaîne de caractère de l'adresse 3 !
• En C++, pas d'erreurs possibles{char *s = "toto";int i = 3;cout << s << " " << i << endl;
}
Programmation objet en langage C++ 64Département Informatique de l'INSA- Jean-Marc Pierson
C++ et Java• C++ n'est pas un langage tout objet, puisqu'il y a
une coexistence entre C et C++• Java s'en rapproche... L'utilisateur ne peut pas
créér des fonctions : ce doit être des méthodes définies dans des classes
• Principales différences :– toutes les classes en Java héritent de la classe Objet– seulement l'héritage simple est défini– pas de pointeurs en Java : notion de références sur les
objets– test de type beaucoup plus complet (Boolean est
different de int !)
C++ et Java (suite)Principales différences (suite)
– les types primitifs ont une taille fixe quelque soit la plate forme de déploiement
– pas de surcharge d'opérateurs– gestion complète des exceptions– pas de fichiers d'inclusions, mais plutôt une
importation de fonctionnalités
• Le code Java compilé est interprété par une JVM afin d'être exécuté
Lire la fin d'un roman policier avant d'y arriver, c'est comme de manger un biscuit fourré à la noix de coco en allant tout de suite à la noix de coco : après il ne reste plus qu'à jeter le biscuit.
----- La ligne verte---- Stephen King