Vous êtes sur la page 1sur 86

2005 - Patrice Jacquemin Libre de droits de diffusion.

TABLE DES MATIERES


PRESENTATION
1. 2. 3. CENTRE DE METZ OBJECTIFS PEDAGOGIQUES PROGRAMME 3.1. Conception et programmation oriente objet avec Java 4. ORGANISATION 5. DESCRIPTION DES HEURES DENSEIGNEMENTS 6. LES MODALITES DE VALIDATION 7. BIBLIOGRAPHIE 8. SITES INTERNET

1
1 1 1 1 1 1 1 1 1

CONCEPTION ET PROGRAMMATION ORIENTEE OBJET AVEC C++ INTRODUCTION LES FONCTIONS EN C++
1. GENERALITES 1.1. Streams et oprateurs de lecture/criture 1.2. Oprateur d'criture << 1.3. Oprateur de lecture >> 1.4. Attribut const 2. PARAMETRES D'UNE FONCTION 2.1. Surcharge de fonctions 3. PASSAGE DE PARAMETRES PAR VALEUR OU PAR REFERENCE 4. PARAMETRES INITIALISES PAR DEFAUT 5. RESULTAT D'UNE FONCTION 5.1. Application du passage de rsultat par rfrence 6. MECANISME INLINE 7. EXERCICES

2 3 4
4 4 4 4 4 5 5 6 7 7 8 9 9

LES CLASSES
1. 2. 3. 4. 5. 6. 7. DEFINITION COMPOSANTS DUNE CLASSE PROTECTION DES MEMBRES INITIALISATION DESTRUCTEUR FONCTIONS MEMBRES EXEMPLE COMPLET DE CLASSE: LA CLASSE FRACTIONS 7.1. Dfinition 7.2. Fonction Somme 7.3. Constructeur Fraction() 7.4. Constructeur Fraction(const int &a) 7.5. Fonction Oppose 7.6. Fonction Est_egal 7.7. Fonction Produit 7.8. Fonction Difference 7.9. Fonction Inverse 7.10. Fonction Quotient 7.11. Fonction Ecrire 7.12. Fonction Lire 8. EXERCICE 8.1. Fonction Det 8.2. Fonctions Pgcd 8.3. Fonction ResoutSystem2x2 8.4. Fonction Simplifie 9. COMPILATION SEPAREE 9.1. Editions des liens 9.2. Inclusion dans les fichiers

13
13 13 13 13 13 13 13 13 14 15 15 15 15 16 16 16 16 16 17 17 17 17 18 18 19 19 19

II
LA SURCHAGE DOPERATEURS
1. 2. DEFINITION CATEGORIE DOPERATEUR 2.1. Oprateur classique : expression x expression expression 2.2. Oprateur : objet x expresion expression 2.3. Oprateur unaire : expresion expression 2.4. Oprateur unaire : objet expression 2.5. Oprateur binaire : expression x expression objet 2.6. Oprateur binaire : expression objet 2.7. Oprateur particulier 3. SYNTAXE DE REDEFINITION 3.1. Syntaxe de dfinition pour une fonction ordinaire 3.1.1. Oprateur binaire 3.1.2. Oprateur unaire 3.2. Syntaxe de dfinition pour une fonction membre 3.2.1. Oprateur binaire 3.2.2. Oprateur unaire 4. EXERCICE 4.1. Oprateur + 4.2. Oprateur - unaire 4.3. Operateur * 4.4. Operateur == 4.5. Operateur < 4.6. Operateur ++ 4.7. Operateur += 4.8. Oprateur << 4.9. Oprateur >> 4.10. Autres oprateurs

20
20 20 20 20 20 20 21 21 21 21 21 21 21 21 21 22 22 22 22 22 22 23 23 23 23 23 24

LES CONVERSIONS
1. CONVERSION A L'AIDE D'UN CONSTRUCTEUR 1.1. Application 1.2. Gnralisation 2. CONVERSION A L'AIDE D'UN OPERATEUR DE CONVERSION 3. CONVERSION EXPLICITE 4. INCONVENIENTS DES CONVERSIONS

25
25 25 26 26 27 27

EXEMPLE COMPLET DE CLASSE


1. 2. 3. 4. RAPPEL SUR LES CHAINES DE CARACTERES EN C EXERCICE LA CLASSE CHAINE FONCTIONS MEMBRES 4.1. Fonction prive Alloue 4.2. Constructeur Chaine(const char *s) 4.3. Constructeur Chaine(const char &ch) 4.4. Constructeur Chaine(const char &c) 4.5. Constructeur Chaine() 4.6. Constructeur Chaine (const Naturel &n, const char &c) 4.7. Destructeur 4.8. Oprateur + 4.9. Oprateur = 4.10. Oprateur [] 4.11. Oprateur <= 4.12. Fonction Ecrire() 4.13. Oprateur << 4.14. Oprateur >> 4.15. Fonction Longueur()

29
29 29 30 31 31 31 31 31 31 32 32 32 32 33 33 33 34 34 34

LHERITAGE ET LES CLASSES DERIVEES


1. 2. 3. INTRODUCTION HERITAGE ET CONVERSION PROTECTION DES MEMBRES ET HERITAGE

35
35 35 36

LES FONCTIONS VIRTUELLES

39

III
LES CLASSES ABSTRAITES LES PATRONS (TEMPLATES)
1. 2. 3. INTRODUCTION MODELE DE FONCTION MODELE DE CLASSE

40 41
41 42 42

LES EXCEPTIONS PROJET ANNUEL PROJET ANNUEL DE PROGRAMMATION ORIENTEE OBJET EN LANGAGE C++
1. 2. 3. 4. ORGANISATION DU TRAVAIL TRAVAIL DEMANDE MODALITES DE LA SOUTENANCE SUJET 4.1. Problme 1. Gestion de fichiers gnriques 4.1.1. Cahier des charges de la classe fichier de X 4.1.2. Gestion des erreurs 4.2. Problme 2 : Gestion densembles gnriques 4.2.1. Cahier des charges de la classe Ensemble de X : 4.3. Problme 3. Drivation formelle

45 46 47
47 47 47 47 47 47 47 47 48 48

ANNEXES PROGRAMMES
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. ENTIERS.H ENTIERS.CPP ERREURS.H ERREURS.CPP FRACTIONS.H FRACTIONS.CPP SYSTEMES.H SYSTEMES.CPP CHAINES.H CHAINES.CPP

49 50
50 50 50 50 51 52 55 55 56 56

LES LIBRAIRIES
1. 2. LINTERET DES LIBRAIRIES LIBRAIRIE C STANDARD 2.1. generalites (#include <stdarg.h>) 2.2. stdio (#include <stdio.h>) 2.3. stdlib (#include <stdlib.h>) 2.4. math (#include <math.h>) 2.5. ctype (#include <ctype.h>) 2.6. string (#include <string.h>) 2.7. signal (#include <signal.h>) 3. IOSTREAM (#INCLUDE <IOSTREAM.H>) 3.1. ostream 3.2. istream 3.3. iostream 3.4. Etat dun flot 3.5. Association dun flot un fichier 4. L++ (STANDARD COMPONENTS) 5. QUELQUES AUTRES LIBRAIRIES

59
59 59 60 60 66 70 72 73 75 76 76 76 76 77 78 78 79

ANNALES 1ERE SESSION 2002/2003


1. EXERCICE 1 : QUESTIONS A CHOIX MULTIPLE

80 81
81

PRESENTATION

PRESENTATION
UV 16472 : B3 - Conception et dveloppement du logiciel. 1 valeur de cours 140 heures. Responsable national : Louis DEWEZ professeur des universits. Les coordonnes du secrtariat du responsable national : dewez@cnam.fr .

1.

CENTRE DE METZ

Enseignant : M. MICHEL, dmic@science.univ-metz.fr . Dates : du 3 janvier au juin 2005. Horaires : les lundis (et quelques jeudis) de 18h30 21h30. Lieu : IUT, Ile du Saulcy, METZ.

2.

OBJECTIFS PEDAGOGIQUES

Le cours est conu en deux parties complmentaires. La premire partie traite les aspects fondamentaux des phases de spcification, prototypage, conception dtaille et validation des algorithmes. La deuxime partie traite de la conception gnrale, de l'architecture et de l'intgration des composants logiciels. Le langage Java est prsent et appliqu l'implantation de problmes spcifis en premire partie.

3.

PROGRAMME
3.1. CONCEPTION ET PROGRAMMATION ORIENTEE OBJET AVEC JAVA
Modularit, typage, structures de donnes. classe, objet, hritage. Concurrence, modlisation.

4.

ORGANISATION

Examen partiel et examen continu. L'ensemble des supports (cours, exercices travaux pratiques) sera disponible et mis jour sur le Web (la prsence est cependant indispensable la comprhension).

5.

DESCRIPTION DES HEURES DENSEIGNEMENTS

Cours : 60 heures. Exercices dirigs : 60 heures.

6.

LES MODALITES DE VALIDATION

Examens finals, devoirs hebdomadaires pour BONUS l'examen.

7.

BIBLIOGRAPHIE
Titre Pascal par la pratique (SYBEX). Le Langage C (DUNOD). Le langage C++ (ADDISON WESLEY). Programmation avance en C++ (ADDISON WESLEY). Programmation en C++ (EYROLLES). Java 2 reference complete (FIRST INTERACTIVE). Au Coeur de Java 2 Tome 1 Notions fondamentales, Tome 2 Fonctions avances (CAMPUS PRESS).

Auteurs P. LEBEUX KERNIGHAN & RICHIE BJARNE STRSUSTRUP J. OLOGHIEN C. DELANNOY SCHILDT HARTSMANN

8.

SITES INTERNET

Conception et programmation oriente objet avec C++

CONCEPTION ET PROGRAMMATION ORIENTEE OBJET AVEC C++

Conception et programmation oriente objet avec C++

INTRODUCTION

INTRODUCTION
Le langage C++ est dit langage de programmation orient objet (LOO). De nombreux autres langages orientes objet existent tels Smalltalk, Simula, Java, Ada. Le concept du LOO a merg assez naturellement aprs plusieurs dizaines dannes dexprience de programmation. On peut dire quelle est la dernire volution des langages de programmation. Historiquement lvolution a t : Le langage machine (1950). Lassembleur (annes 50). Les langages de haut niveau (annes 70). Ils ont apport la notion de typage. Pascal, Fortrant (57), Cobol, C. LOO. C++ (80/90), smalltalk (70), simula, java (95). Lassembleur est encore trs utilis notamment dans les domaines des automates, du temps rels, lexploitation de puces . Il est caractris par son haut niveau de performances et le peu de place requis en mmoire. Les LOO ont un intrt pour les trs gros programmes ncessitant de nombreuses lignes de codes. Les LOO peuvent utiliser des couches en C pour les performances. Java a pour caractristique sa portabilit en contrepartie du cot lev du temps dexcution, du temps machine. Au cours de cette volution les langages sloignent des contraintes du matriel et se rapprochent soit du langage mathmatique ou du langage naturel. Les LOO permettent dadapter la programmation la rsolution du problme trait quel que soit le domaine (CAO, base de donnes, gnie logiciel, rseau). Les LOO tentent (russissent ?) dapporter des solutions aux problmes rencontrs aux langages classiques surtout lors de la rsolution de logiciels de grandes tailles. Ils apportent , par rapport ces derniers, une plus grande souplesse de programmation, une meilleure rigueur de programmation, la possibilit de contrler trs efficacement le code produit, un meilleur formalisme trs algbrique, une meilleure rutilisabilit du code. Mise en garde: une plus grande souplesse de programmation entrane plus de contrle laiss la machine, donc plus de dcisions laisses la machine d'o des ambiguts voir mme des bugs ! En conclusion: la grande libert accorde au programmeur ne doit pas tre ralise au dtriment de la rigueur. Il faut au contraire exploiter les possibilits du langage pour produire un code plus sr. Le concept cl des LOO est la notion de classe. En programmation classique il y a sparation complte entre les donnes et le traitement. Les LOO, au contraire, proposent de runir donnes et traitement en une seule entit : la classe. Ainsi on peut dfinir les objets avec leur structure, les oprations sur les objets, les proprits de ces objets et runir le tout en une seule dfinition. La classe introduit, entre autres, deux notions importantes : La protection des membres. La possibilit dinitialiser un objet ds sa cration. Il en dcoule quun objet a la possibilit de parfaitement contrler les oprations faites sur lui. Il est toujours responsable des traitements effectus sur lui ce qui donne un meilleur contrle des logiciels, une facilit de dbugage, une programmation plus simple. Les autres notions importantes pour les LOO sont : Lhritage. Le polymorphisme. La gnricit (les patrons). Remarque sur le C++ : ce langage reprends et tends le langage C, ce qui explique sa grande diffusion. Donc le langae C est un sous-ensemble de C++. En consquence : Tout ce quil est possible de faire en C lest en C++. Une certaine redondance entre les deux langages existe. Note de lauteur : les diffrents programmes ont t tests et valids en utilisant lIDE Dev-C++ 5.0 beta 9.2 (4.9.9.2) avec Mingw/GCC 3.4.2 que vous trouverez sur http://www.bloodshed.net/dev/devcpp.html , voir galement http://www.bloodshed.net/ . Ils sont prcds de la marque . Remerciements Alain Beck pour linformation.

Conception et programmation oriente objet avec C++

LES FONCTIONS EN C++

LES FONCTIONS EN C++


1. GENERALITES
1.1. STREAMS ET OPERATEURS DE LECTURE/ECRITURE
En C++ les fichiers (FILE *) ont t avantageusement remplacs par les flux (streams). On peut considrer que les flux sont des sortes de super fichier . Parmi les diffrentes sortes de flux, il y a les flux d'entre (classe istream) et les flux de sortie (classe ostream ). Les classes istream et ostream sont dcrites dans le fichier header iostream.h. cout est une variable globale de type ostream (en faite une instance de la classe ostream) et correspond la sortie standard (par dfaut l'cran). cin est une variable globale de type istream (en faite une instance de la classe istream) et correspond l'entre standard (par dfaut le clavier).

1.2. OPERATEUR D'ECRITURE <<


La classe ostream est munie d'un oprateur d'affichage << qui remplace la fonction printf du C. Il permet d'afficher n'importe quel type de donnes l'cran. Il reconnat les types de donnes et permet donc d'viter l'emploi des formats fastidieux de printf. Exemple: #include <iostream.h> using namespace std; main() //programme principal { float x=3; double y=2.5; int i=2; cout << x; //affiche la valeur de cout << y; //affiche la valeur de cout << i; //affiche la valeur de cout << c; //affiche la valeur de cout << "x= " << x << "y= " << y ligne + retour ligne }

char *c="abc"; x sur la console y sur la console i sur la console c sur la console << "i= " << i << "c= " << c << "\n"; //endl :fin de

1.3. OPERATEUR DE LECTURE >>


Il est le symtrique de l'oprateur <<. La classe istream est munie de l'oprateur >> (oprateur de lecture) qui remplace la fonction scanf du C. Il permet de lire n'importe quelles donnes, prdfinies du C, au clavier. Il reconnat les types et se passe donc de format. Exemple: #include <iostream.h> using namespace std; main() //programme principal { float x; double y; char c[10]; cout << "Tapez un rel \n"; cin >> x; //x reoit la valeur entre au clavier cout << "Encore un rel \n"; cin >> y; cout << "Tapez une chane d'au plus 9 caractres \n"; cin >> c; //ou bien en combinant les appels: cin >> x >> y >> c; //espace ou tab pour distinguer les donnes }

1.4. ATTRIBUT CONST


L'attribut const permet de dclarer qu'une chose soit constante. Il a pour effet que la chose dclare constante n'a pas le droit d'tre place gauche d'oprateur d'affectation ( op {+,-,*, /,%, <<, >>,|, &,||, &&,^} ) car ces oprateurs modifient leur oprande gauche. Et de manire gnrale, une chose dclare constante n'a pas le droit d'tre modifie. La chose peut tre une variable , un paramtre d'une fonction ou un rsultat d'une fonction. Exemple : using namespace std; main() { const int x; x = 4; //refus

Conception et programmation oriente objet avec C++

5
const int y = 3; //refus const int z(7); z = 8; //refus }

LES FONCTIONS EN C++

struct Vecteur //struct :mot cl pour dfinir une classe sans mthode { double x,y; }; //ne pas oublier le; la fin de la classe main() { Vecteur v; v.x = 3; v.y = 5; const Vecteur u; u.x = 7; //refus car u est constant } Remarque : les paramtres et les rsultats d'une fonction en C++ sont aussi structures que vous voulez. Exemple: fonction calculant la somme de deux vecteurs. #include <iostream.h> using namespace std; Vecteur Somme(Vecteur a, Vecteur b) { Vecteur r; r.x = a.x + b.x; r.y = a.y + b.y; return r; } main() { Vecteur u,v,w; u.x = u.y = 3; v.x = -1; v.y=9; w = Somme(u,v); cout << "rsultat de vecteur u(" << u.x << "," << u.y << ") + vecteur v(" << v.x << "," << v.y << ") = vecteur w(" << w.x << "," << w.y << ")" << endl; }

2.

PARAMETRES D'UNE FONCTION


2.1. SURCHARGE DE FONCTIONS

Plusieurs fonctions peuvent avoir le mme nom. A l'appel, la distinction se fait grce la nature des paramtres et/ou au nombre de paramtres. Exemple : #include <iostream.h> using namespace std; double max(double a, double b) //calcul le maximum de a et b { if (a > b) return a; //quivalent en C: (a > b ? a : b); else return b; } double max(double a, double b, double c) { return max(a,max(b, c)); } main() { double x, z, y; x = 7; y = 4; z = 11; cout << "max(" << x << "," << y << ")=" << max(x,y) << endl; cout << "max(" << x << "," << y << "," << z << ")=" << max(x,y,z); }

Conception et programmation oriente objet avec C++

6
! x ! Exemple : U U = y x +y
2 2

LES FONCTIONS EN C++


x ! ! et V y V = z

x2 + y2 + z2

# include <math.h> #include <iostream.h> using namespace std; struct Vecteur2D { double x,y; }; struct Vecteur3D { double x,y,z; }; double Norme(Vecteur2D u) { return sqrt(u.x * u.x + u.y *u .y); } double Norme (Vecteur3D u) { return sqrt(u.x * u.x + u.y * u.y + u.z * u.z); } main() { Vecteur2D u ={7,3}; Vecteur3D v = {-4,7,3}; cout << "||u||= " << Norme(u) << "||v||= " << Norme(v) << "\n"; }

3.

PASSAGE DE PARAMETRES PAR VALEUR OU PAR REFERENCE

Les paramtres d'une fonction sont passs soit par valeur, soit par rfrence (notions indpendantes des langages de programmation). En C le passage de paramtres par rfrence n'existe pas, il est simul l'aide de pointeurs. En C++ les deux modes de transmission existent. Par dfaut, un paramtre est pass par valeur (et un paramtre pass par rfrence est prcd du symbole "&"). Exemple : #include <iostream.h> using namespace std; void F(int a, int &b) { cout <<"a= " << a << " b= " << b << "\n"; ++a; ++b; //quivaut b = b + 1 cout << "a= " << a << " b= " << b << "\n"; } main() { int x,y; x = 4; y = 7; cout << "x= " << x << " y= " << y << "\n"; F(x,y); cout << "x= " << x << " y= " << y << "\n"; }
x y mmoire 1 4 7 x b,y a Console 2 F 1 2 x=4 a=4 a=5 3 x=4 y=7 b=7 b=8 y=8 2 4 7 4 Copie x y 3 4 7

main

A ltape 2 a est transmis par valeur. x est dit paramtre effectif, a est dit paramtre formel. Conclusion: La fonction F modifie le paramtre y car elle travaille avec l'original : b est un autre nom pour accder au mme emplacement mmoire, x n'est pas modifi car F travaille avec ce qui est une copie temporaire de x. Le passage de paramtres par valeur est utilis pour communiquer des donnes dans le sens du programme appelant vers fonction. Il laisse le paramtre intact : utilis lorsque la fonction doit consulter un paramtre sans le modifier. Le passage de paramtres par valeur est plus coteux en temps et en espace mmoire, augmentant en fonction de la taille du paramtre.

Conception et programmation oriente objet avec C++

LES FONCTIONS EN C++

Le passage de paramtres par rfrence est utilis pour communiquer des rsultats dans le sens fonction vers programme appelant. Il permet de modifier le paramtre : utilis lorsque la fonction devra ranger un rsultat par le biais de ce paramtre Le passage de paramtres par rfrence est plus conomique en temps d'excution, espace mmoire, car il conomise le temps de raliser la copie et il n'exige pas d'espace mmoire supplmentaire Un paramtre peut tre une donne de la fonction (entre), un rsultat de la fonction (sortie), une donne et rsultat (entre/sortie). Lorsque le paramtre est de grande taille, le passage de paramtres par valeur peut devenir trs coteux en temps et espace. Il peut tre intressant de passer par rfrence mme s'il doit tre simplement consult par la fonction. Exemple : Vecteur Somme(Vecteur &a, Vecteur &b) { Vecteur r; r.x = a.x + b.x; r.y = a.y + b.y; return r; } Le problme d'crire cela de cette faon, c'est que l'on peut modifier les vecteurs passs en paramtre alors que ce sont des donnes. De plus si l'on travaille en quipe, les autres peuvent penser que l'on modifie les vecteurs passs par paramtre alors que ce n'est pas le cas. Il faudrait donc crire la fonction de cette faon: Vecteur Somme(const Vecteur &a, const Vecteur &b){} Avec l'attribut const, cette fonction reste rigoureuse en ayant les avantages du passage de paramtre par rfrence.

4.

PARAMETRES INITIALISES PAR DEFAUT

II est possible en C++ que certains paramtres soient initialiss par dfaut. Si l'appel, des paramtres effectifs manquent, les valeurs par dfaut sont utilises. Exemple : #include <iostream.h> using namespace std; struct Vecteur3D { double x,y,z; }; Vecteur3D CreeVecteur3D(const double &a = 8, const double &b = -12, const double &c = 9) { Vecteur3D R; R.x = a; R.y = b; R.z = c; return R; } main() { Vecteur3D u,v,w,t; u = CreeVecteur3D(4,8,-11); v = CreeVecteur3D(7,0); //v = CreeVecteur3D(7,0,9) w = CreeVecteur3D(5); // w = CreeVecteur3D(5,-12,9) t = CreeVecteur3D(); // t = CreeVecteur3D(8,-12,9) }

5.

RESULTAT D'UNE FONCTION

Celui renvoy par linstruction return. Par dfaut le rsultat d'une fonction est pass par valeur (c'est le passage classique), mais en C++, il est possible de passer un rsultat par rfrence. C'est dire qu'une fonction peut renvoyer non pas une expression mais un objet. Rappel sur la diffrence entre une expression et un objet : Un objet reprsente un espace mmoire. En consquence on peut lui affecter quelque chose, il peut tre plac gauche dun oprateur daffectation, on peut en prendre ladresse. Une expression ne correspond pas un espace mmoire. En consquence on ne peut pas lui affecter quelque chose, elle ne peut pas tre place gauche dun oprateur daffectation, on peut en prendre ladresse. Exemple :

Conception et programmation oriente objet avec C++

8
main() { int a,b,c; float x; char t[5]; Vecteur A; x; //objet sqrt(x); //expression a + b; //expression t[2]; //objet 3; //expression t; //expression A.x; //expression "abc"; //expression }

LES FONCTIONS EN C++

Une fonction ne peut prendre un rsultat par rfrence que si ce rsultat est un objet persistant : Objet : espace mmoire. Persistant : survit lappel de la fonction.

5.1. APPLICATION DU PASSAGE DE RESULTAT PAR REFERENCE


Comme pour la passage de paramtres par rfrence, la passage de rsultat par rfrence sert : Modifier un objet par le biais de lappel la fonction. Consquence : lappel la fonction peut tre plac gauche dun oprateur daffectation. Sert optimiser le passage du rsultat en temps et en espace. Exemple : main() { int a,b,c; a = 5; b = 3; a += b; c = a += b; //c= a; a= a + b; (a += b) = c; //refus } Ecrire une fonction Ajout qui simule += pour les vecteurs : void Ajout(Vecteur const Vecteur &b) /*effectue a += b*/ { a.x += b.x; a.y += b.y; } &a, #include <iostream.h> using namespace std; main() { Vecteur u,v; u.x = 3; u.y = 7; v.x = 11; v.y = -4; cout << "Ajout[u(" << u.x << "," << u.y << "),v(" << v.x << "," << v.y << ")] = "; Ajout(u,v); cout << "vecteur u(" << u.x << "," << u.y << ")" << endl;} Donnes : u,v. Rsultat : u. Vecteur &Ajout(Vecteur &a, const Vecteur &b) /*effectue a += b*/ { a.x += b.x; a.y += b.y; return a; } #include <iostream.h> using namespace std; main() { Vecteur u,v,w; u.x = 3; u.y = 7; v.x = 11; v.y = -4; w = Ajout(u,v); } Donnes : u,v. Rsultat : w. Mmoire a,u 3 7 11 -4 14 w 3 Mmoire 3 7 11 -4 14 3

a,u

b,v

b,v

Conception et programmation oriente objet avec C++

LES FONCTIONS EN C++

Exemple abrant (ou exemple de ce qu 'il ne faut pas faire) : int &f(int a, int b) { int t; t = a + b; return t; } main() { int *p; //* signifie pointeur sur entier p = &f(2,3); //p reoit adresse de f donc p prends adresse de t *p=10; }

6.

MECANISME INLINE

Les mcanismes inline gnralisent les macros du langage C. Il s'agit d'une substitution de texte. Exemple de macro : #define PI 3.1415926 #define abs(x) ((x) > 0 ? (x) : -(x)) main() { double teta, alfa, x; int a; teta = PI / 2; alfa = PI / 4; x = 7; teta = abs(x); x = abs(a); } inline int Max(const int &a, const int &b) { return (a > b ? a : b); } main() { int u, v; u = 7; v = 9; cout << Max(u,v); cout << (u > v ? u : v); cout << Max(15, 3); cout << (15 > 3 ? 15 : 3); } Avantage du mcanisme inline : plus rapide que dcrire des vrais fonctions. Inconvnient du mcanisme inline : rallonge la taille de lexcutable. Conclusion: pour tirer profit au maimum de ce mcanisme, on le rserve de petites fonctions appeles trs souvent. Mais ne pas utiliser pour les traitements rcursifs.

7.

EXERCICES

Ecrire une fonction qui rsout une quation dans " ax2 + bx + c = 0 avec a, b, c " et une fonction main qui utilise la fonction crite pour rsoudre une quation dont les paramtres sont donnes par lutilisateur. Exemple : 3x - 7x + 4 = 0. Mthode classique avec a 0. = b2 4ac
si > 0 deux solutions : x1 = b b + et x2 = 2a 2a b a

si = 0 solution double : x =

si < 0 pas de solution relle Les donnes sont a, b, c et le rsultat x1et x2.

Conception et programmation oriente objet avec C++

10
#include <iostream.h> using namespace std;

LES FONCTIONS EN C++

bool ResoutEquationDegre2(const double &a, const double &b,const double &c, double &x1, double &x2) /*donnes a, b, c hypothse a 0 Tache : rsout dans " ax2 + bx + c = 0 Rsultats : x1 et x2 et un boolen Convention : si renvoie vrai alors x1 et x2 ont t calcul Si renvoie faux alors x1 et x2 sont indtermins*/ { if (a == 0) return false; long delta = b * b 4 * a * c; if (delta >= 0) { x1 = ((-b) sqrt(delta)) / (2 * a); x2 = ((-b) + sqrt(delta)) / (2 * a); return true; } else return false; } Attention : il se pose un problme avec les doubles quand les nombres ne sont pas de la mme grandeur : larrondi. Le test sur le 0 est difficile if (delta == 0). #include <iostream.h> using namespace std; bool ResoutEquationDegre2(const double &a, const double &b, const double &c, double &x1, double &x2) /*donnes a, b, c hypothse a 0 Tache : rsout dans " ax2 + bx + c = 0 Rsultats : x1 et x2 et un boolen Convention : si renvoie vrai alors x1 et x2 ont t calcul Si renvoie faux alors x1 et x2 sont indtermins*/ { if (a == 0) return false; double delta; delta = b * b 4 * a * c; if (delta < 0) return false; else /*delta >= 0*/ { double r; r = sqrt(delta); x1 = (-b r) / (2 * a); x2 = (-b + r) / (2 * a); return true; } } main() { double p, q, r, x, y; cout << Rsolution dans " de ax2 + bx + c = 0, tapez les valeurs de a, b, c avec a diffrent de 0\n; cin >> p >> q >> r; if (ResoutEquationDegre2(p, q, r, x, y)) cout << Les solutions sont << x << et << y << endl; else cout << "Pas de solution relle\n"; } Une racine carre se calcule sous la forme dune suite :
n+

lim Un =

x avec x 0

U0 = 1 Un = 1 x Un1 + 2 Un1

Conception et programmation oriente objet avec C++

11

LES FONCTIONS EN C++

Ecrire un programme qui rsout le systme suivant (avec a, b, c, a, b, c dans " ) : ax + by = c a ' x + b ' y = c '
Mthode de Kramer Calculer det = a b = ab ' a 'b a' b'

c b c' b' cb ' c 'b ac'-a'c = si det 0 alors x= et y= det det det si det = 0 alors de sol ou pas de solution Les donnes sont a1, a2, b1, b2, c1, c2 et le rsultat x, y et un boolen.
#include <iostream.h> using namespace std; double det(const double &a11, const double &a12, const double &a21, const double &a22) a11 a12 */ /* calculer a21 a22 { return a11 * a22 - a21 * a12; } bool ResoutSystem2x2(const double &a1, const double &a2, const double &b1, const double &b2, const double &c1, const double &c2, double &x, double &y) /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ { double d; d = det(a1,b1,a2,b2); // d = a1 * b2 a2 * b1; if (d == 0) return false; else /*d 0*/ { x = (c1 * b2 c2 * b1) / d; //x = det(c1,b1,c2,b2) / d; y = (a1 * c2 c1 * a2) / d; //y = det(a1,c1,a2,c2) / d; return true; } } main() { double a1, a2, b1, b2, c1, c2, x, y; cout << "Entrez les coefficients de la premiere equation : "; cin >> a1 >> b1 >> c2; cout << "Entrez les coefficients de la seconde equation : "; cin >> a2 >> b2 >> c2; if (ResoutSystem2x2(a1, a2, b1, b2, c1, c2, x, y)) cout << "x= " << x << " y= " << y << "\n"; else cout << "pas de solution\n"; }

Solution pour le test sur d == 0 : FLT_EPSILON. Cest la limite des plus petits nombres flottants.
#include <iostream.h> #include <float.h> using namespace std; bool ResoutSystem2x2(const double &a1, const double &a2, const double &b1, const double &b2, const double &c1, const double &c2, double &x, double &y, const double &EPS = FLT_EPSILON) /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen

Conception et programmation oriente objet avec C++

12

LES FONCTIONS EN C++

Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ { double d; d = det(a1,b1,a2,b2); if (fabs(d) < EPS) return false; else /*d 0*/ { x = det(c1,b1,c2,b2) / d; y = det(a1,c1,a2,c2) / d; return true; } }

Conception et programmation oriente objet avec C++

13

LES CLASSES

LES CLASSES
1. DEFINITION
La classe est une entit qui regroupe des structures de donnes (comme un type record du Pascal, ou struct du C) et les oprations associes ces donnes. Cest un concept trs algbrique, les instances de la classe (aussi appeles exemplaires ou objet) sont vu comme les lments dun ensemble mathmatique. La classe est donc une entit ou sont dcrites simultanment la structure, les proprits et oprations possibles sur les instances.

2.

COMPOSANTS DUNE CLASSE

Les composants dune classe sont appels aussi membres (ou encore champs = fields). Les membres peuvent tre indiffremment des donnes ou des traitements. Les traitements sont encore appels fonctions membres ou mthodes.

3.

PROTECTION DES MEMBRES

Les membres (indiffremment donnes ou traitements) peuvent tre publiques (public), privs (private) ou protgs (protected). La notion de membre protg est lie lhritage. Si un membre est dclar public toutes fonctions extrieures la classe et toute fonction de la classe y ont accs. Si un membre est dclar priv seules les fonctions membres de la classe y ont accs (en consultation et modification). En rsum : une classe comporte gnralement une partie prive dans laquelle sont dcrits les membres que seule la classe gre et une partie public servant dinterface avec les autres classes et o sont dcrits les membres accessibles lensemble des classes. Cette organisation est la mme que celle de celle de la compilation spare. Cest la mme notion galement que la notion de module modle/primitives daccs.

4.

INITIALISATION

Il est possible, et par suite recommande, de dfinir pour une classe une fonction membre particulire. Le constructeur servant a initialiser tout exemplaire ds sa cration (il est appel automatiquement). Il garantit que tout objet est correctement initialis. Il sert galement de fonction de cration, d'un exemplaire de la classe et il peut galement servir raliser des conversions.

5.

DESTRUCTEUR

Voir plus loin.

6.

FONCTIONS MEMBRES

Pour les fonctions membres il y a existence d'un argument explicite : c'est l'instance pour laquelle la fonction membre est appele. Cette instance constitue toujours un argument de la fonction. Elle est toujours accessible et un pointeur est toujours associ cet instance : le pointeur this. L'argument implicite est toujours pass par rfrence.

7.

EXEMPLE COMPLET DE CLASSE: LA CLASSE FRACTIONS

Supposons que lon dsire un logiciel qui utilise la notion de fraction. Module dune fraction : a a # ( entier relatif sign ) , b $* ( entier 1) b

7.1. DEFINITION
Voir en annexe le fichier complet testfractions.cpp.
#include <iostream> using namespace std; typedef unsigned int Naturel; class Fraction { /*par dfaut priv*/ int num; // numrateur Naturel den; // dnominateur >= 1 public: /*dclaration de ce qui est public jusqu main() { Fraction x1(2,3); Fraction x2(-1,4); /*appel du constructeur passage des paramtres*/ }

Mmoire x1 x2 2 3 -1 4 num den num den

Conception et programmation oriente objet avec C++

14

LES CLASSES

nouvel ordre*/ Fraction(const int &a, const Naturel &b); // constructeur cre a/b on suppose b 0 }; // ne pas oublier le; /*le constructeur porte le mme nom que la classe*/ /*rfrencement de la fonction la classe*/ Fraction :: Fraction(const int &a, const Naturel &b) /* constructeur cre a/b on suppose b 0*/ { if (b == 0) Erreur("Fraction :: Fraction(a,b) : b == 0"); if (b > 0) { num =a; den = b; } else /*b < 0*/ { num = - a; den = (Naturel)(-b); } } Le constructeur tel que dfini est sur demploi. /*dfinition de la fonction erreur*/ void Erreur(char* message) { cerr << \n\nErreur ! << message << endl; exit (0); }

7.2. FONCTION SOMME


Par convention on rajoute la fonction tudie dans une version simplifie de la classe.
class Fraction { public: Fraction Somme(const Fraction &a) const; // le dernier const signifie que la fonction membre ne modifie pas largument implicite }; main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3(0,1); x3 = x1.Somme(x2); // x1 est largument implicite }

Mmoire x1 x2 x3 this r 0 1 5 12 2 3 -1 4 7 1 *this

Fraction Fraction :: Somme(const Fraction &a) const { Fraction r(0,1); r.num = (*this).num * a.den + (*this).den * a.num; // simplification r.num = num * a.den + den * a.num; r.den = (*this).den * a.den; // simplification r.den = den * a.den; return r; }

1re optimisation de la fonction membre Somme : Fraction Fraction :: Somme(const Fraction &a) const { Fraction r(num * a.den + den * a.num, den * a.den); return r; } 2me optimisation de la fonction membre Somme : Fraction Fraction :: Somme(const Fraction &a) const { return Fraction(num * a.den + den * a.num, den * a.den); }

Conception et programmation oriente objet avec C++

15

LES CLASSES

Equivalence dcriture : x4 = x3.Somme(x1.Somme(x2)); <=> x4 = x3.Somme(x1).Somme(x2); x4 = Fraction(2,3).Somme(x1);

7.3. CONSTRUCTEUR FRACTION()


class Fraction { public: Fraction(); // cre 0 / 1 }; Fraction :: Fraction() // cre 0 / 1 { num = 0; den = 1; }

7.4. CONSTRUCTEUR FRACTION(CONST INT &A)


class Fraction { public: Fraction(const int &a); // cre a / 1 }; Fraction :: Fraction(const int &a) // cre a / 1 { num = a; den = 1; }

7.5. FONCTION OPPOSE


class Fraction { public: Fraction Oppose() const; // renvoie loppos de largument implicite }; main() { Fraction x1(2,3); Fraction x2(-1,4); x1 = x2.Oppose(); }

Fraction Fraction :: Oppose() const /*renvoie (*this)*/ { Fraction r; r.num = -(*this).num r.den = (*this).den; return r; }

Optimisation de la fonction Oppose() : Fraction Fraction :: Oppose() const /*renvoie (*this)*/ { return Fraction(-num, den); }

7.6. FONCTION EST_EGAL


class Fraction { public: bool Est_egal(const Fraction &a) const; }; bool Fraction :: Est_egal(const Fraction &a) const { Return num * a.den == den * a.num; } main() { Fraction x1(2,3); Fraction x2(-1,4); bool ok; ok = x1.Est_egal(x2); }

Conception et programmation oriente objet avec C++

16

LES CLASSES

7.7. FONCTION PRODUIT


class Fraction { public: Fraction Produit(const Fraction &a) const; }; main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x3 = x1.Produit(x2); }

Fraction Fraction :: Produit(const Fraction &a) const { return Fraction(num * a.num, den * a.den); }

7.8. FONCTION DIFFERENCE


class Fraction { }; Fraction Difference(const Fraction &a, const Fraction &b); main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x3 = Difference(x1,x2); }

Fraction Difference(const Fraction &a, const Fraction &b) { return a.Somme(b.Oppose()); }

Faire une fonction ordinaire (non membre) permet dallger la maintenance en cas de changement dans la classe, cellei nest pas dans la classe et sera mise jour automatiquement. Elle utilise des fonctions membres.

7.9. FONCTION INVERSE


class Fraction { public: Fraction Inverse() const; }; main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x3 = x1.Inverse(); }

Fraction Fraction :: Inverse() const { return Fraction(den,num); }

7.10. FONCTION QUOTIENT


class Fraction { }; Fraction Quotient(const Fraction &a, const Fraction &b); main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x3 = Quotient(x1,x2); }

Fraction Quotient(const Fraction &a, const Fraction &b) { return a.Produit(b.Inverse()); }

7.11. FONCTION ECRIRE


class Fraction { public: void Ecrire(ostream &os) const; }; main(){ Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x1.Ecrire(cout); }

Conception et programmation oriente objet avec C++

17

LES CLASSES

void Fraction :: Ecrire(ostream &os) const { os << num << / << den; }

Le paramtre de la fonction nest pas considr comme un const car laction crire modifie le fichier. Lcran est considr comme un fichier par le systme.

7.12. FONCTION LIRE


class Fraction { }; Fraction Lire(istream &is); Fraction Lire(istream &is) { int a,b; is >> a >> b; return Fraction(a,b); } main() { Fraction x1(2,3); Fraction x2(-1,4); Fraction x3; x3 = Lire(cin); }

8.

EXERCICE

3 1 2 5 x + 4 y = 3 Rsoudre le systme dquation tel que : 7 x 7 y = 1 4 3 2 Les coefficients, connus sous forme de fractions, sont saisis au clavier. Les solutions, si elles existent, sont calcules sous forme de fraction.

8.1. FONCTION DET


Fraction Det(const Fraction &a11, const Fraction &a12, a a12 const Fraction &a21, const Fraction &a22); /*calcule 11 */ a21 a22 Fraction Det(const Fraction &a11, const Fraction &a12, const Fraction &a21, const Fraction &a22) a a12 /*calcule 11 */ a21 a22 { } return Difference(a11.Produit(a22), a21.Produit(a12));

8.2. FONCTIONS PGCD


Naturel Pgcd1(const Naturel &a, const Naturel &b); /*calcule le pgcd de a et b, hypothse a >= 1 b >= 1*/ Naturel Pgcd(const int &a, const int &b); /*on suppose (a,b) (0,0)*/ #include <stdlib.h> Naturel Pgcd(const int &a, const int &b) /*on suppose (a,b) (0,0)*/ { if (a == 0) return abs(b); else /*a 0*/ if (b == 0) return abs(a); else /* a 0 et b 0*/ return Pgcd1(abs(a),abs(b)); }

Conception et programmation oriente objet avec C++

18

LES CLASSES

Version itrative de la fonction Pgcd1 : Naturel Pgcd1(const Naturel &a, const Naturel &b) /*calcule le pgcd de a et b, hypothse a >= 1 b >= 1*/ { Naturel x, y; x = a; y = b; while (x != y) { if (x > y) x -= y; else /*x < y*/ y -= x; } return x; } Version rcursive de la fonction Pgcd1 : Naturel Pgcd1(const Naturel &a, const Naturel &b) /*calcule le pgcd de a et b, hypothse a >= 1 b >= 1*/ { if (a == b) return a; // cas trivial else if (a > b) return Pgcd1(a b,b); // cas gnral else /*a < b*/ return Pgcd1(a,b - a); // avec un sous problme }

8.3. FONCTION RESOUTSYSTEM2X2


bool ResoutSystem2x2(const Fraction &a1, const Fraction &b1, const Fraction &a2, const Fraction &b2, const Fraction &c1, const Fraction &c2, Fraction &x, Fraction &y); /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ bool ResoutSystem2x2(const Fraction &a1, const Fraction &b1, const Fraction &a2, const Fraction &b2, const Fraction &c1, const Fraction &c2, Fraction &x, Fraction &y) /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ { Fraction d = Det(a1,b1,a2,b2), zero; if (d.Est_egal(zero)) return false; // pas darrondi car ce sont des entiers else { x = Quotient(Det(c1,b1,c2,b2),d); y = Quotient(Det(a1,c1,a2,c2),d); return true; }

8.4. FONCTION SIMPLIFIE


class Fraction { Public: Fraction Simplifie() const; }; Fraction Fraction :: Simplifie() const { Naturel p; p = Pgcd(num,den); return Fraction(num / p,den / p); }

Conception et programmation oriente objet avec C++

19
9. COMPILATION SEPAREE

LES CLASSES

Il sagit, en premier lieu, de rpartir le code en module ou unit. Fractions classe Fraction Lire Quotient Difference Erreurs Erreur Systmes Det ResoutSystem2x2 Entiers Pgcd Pgcd1 Naturel Programme main

Chaque module se dcompose en deux fichiers : Le *.h correspond aux enttes. Il contient les dfinitions utiles dans le module : o Les types. o Les constantes. o Les classes o Les enttes de mthodes. o Les commentaires. Le *.cpp contient les corps des mthodes dfinies dans le fichier *.h accompagnes des fonctions ordinaires. On compile ensuite chacun des fichiers avec la commande g++ -c du compilateur g++ sous linux.

9.1. EDITIONS DES LIENS


Elle fournit un seul fichier excutable indpendant du langage de programmation.

9.2. INCLUSION DANS LES FICHIERS


Un premier type dinclusion concerne les fichiers o se trouvent des fonctions non dfinies dans le fichier courant. Il faut inclure le fichier contenant les dfinitions des fonctions appeles dans ce fichier. Lordonnancement des include suit celui des appels de fonctions !! Si le fichier inclure est dans le mme rpertoire : #include fichier.h Dans un rpertoire diffrent : #include <fichier.h> Chaque fichier *.cpp fait appel au fichier *.h correspondant et ncessite donc une inclusion de celui-ci. Exemple pour fractions.cpp : #include <iostream> #include erreurs.h #include entiers.h #include fractions.h Une fonction pouvant tre appele dans diffrents fichiers, il en serait de mme pour le fichier *.h concern entranant une erreur. Pour y palier, on teste lexistance dune constante : Si oui, on quitte le fichier. Si non, on la dfinit et le fichier est lu entirement. Exemple pour fraction.h : #ifndef FRACTIONSH #define FRACTIONSH
using namespace std; typedef unsigned int Naturel; class Fraction { }; #endif

Conception et programmation oriente objet avec C++

20

LA SURCHAGE DOPERATEURS

LA SURCHAGE DOPERATEURS
1. DEFINITION
La surcharge doprateur consiste faire signifier un oprateur une autre opration que celle pour laquelle il tait initialement prvu. Pour surcharger un oprateur il faut crire sous forme de fonction, loprateur que lon dsire associ cette opration. Cela signifie quun oprateur nest rien dautre quune fonction que lon appelle de faon particulire. Le traitement associ cet oprateur surcharg est dfini par le concepteur et na donc aucun lien obligatoire avec loprateur initial. Exemple : Un oprateur + redfini peur trs bien signifi autre chose quune addition. Les seules proprits des oprateurs qui sont conservs lors de la redfinition sont : Larit (le nombre doprande. La priorit. Lassociativit (de gauche droite, de droite gauche). Conseil : il est vivement recommand dutiliser le mcanisme seulement pour tendre les oprations existantes des classes plus complexes. Il est dangereux de faire signifier des oprateurs des oprations qui peuvent surprendre le programmeur. Exemple : loprateur pour une addition ou une lecture. Donc lors de la redfinition dun oprateur arithmtique pour une classe imitez la signification du mme oprateur pour un type simple du C. Avant de redfinir les oprateurs du C il est utile de rappeler certaines proprits et exigences de ces oprateurs. Certains des ces oprateurs sont binaires, dautres unaires, certains exigent quun oprande soit un objet. On peut classer les oprateurs en plusieurs catgories et il convient lors de la redfinition de ne pas changer de catgories un oprateur. Remarque : diffrence entre objet et expression. Un objet reprsente un emplacement mmoire : On peut lui affecter quelque chose : il peut tre plac gauche dun oprateur daffectation. On peut parler de son adresse. Une expression ne reprsente pas une case mmoire : On ne peut rien affecter une expression, ne peut tre gauche dun oprateur daffection. On ne peut en prendre ladresse. Remarque : il est toujours possible partir dun objet dobtenir une expression : en effet il suffit dvaluer lobjet (rcuprer la valeur inscrite dans la case) pour obtenir une valeur. Le contraire nest pas vrai.

2.

CATEGORIE DOPERATEUR
2.1. OPERATEUR CLASSIQUE : EXPRESSION X EXPRESSION EXPRESSION

+ - (binaire) * / == > < => <= % && || != << >> ^ & |


2.2. OPERATEUR : OBJET X EXPRESION EXPRESSION

= op= op {+, -, *, /, %, &&, ||, ^, &, |, <<, >>}


2.3. OPERATEUR
UNAIRE : EXPRESION EXPRESSION

- (unaire) ! ~
2.4. OPERATEUR
UNAIRE : OBJET EXPRESSION

++ -- & (adresse de)


Conception et programmation oriente objet avec C++

21

LA SURCHAGE DOPERATEURS

2.5. OPERATEUR BINAIRE : EXPRESSION X EXPRESSION OBJET

[]
2.6. OPERATEUR BINAIRE : EXPRESSION OBJET

*
2.7. OPERATEUR PARTICULIER

? : ,
Les catgories 1 3 peuvent tre surcharge, la 4 sauf le & et dans la 5 uniquement les [].

3.

SYNTAXE DE REDEFINITION

Un oprateur surcharg peut tre une fonction ordinaire ou une fonction membre.

3.1. SYNTAXE DE DEFINITION POUR UNE FONCTION ORDINAIRE 3.1.1. OPERATEUR BINAIRE
Soit @ un oprateur binaire et trois classes X, Y, Z. On dfinit : Z operator @(Xx,Yy) { // corps de la fonction } A lappel : Zz; Yy; Xx; z = x @ y; //<=> z = operator @(x,y);

3.1.2. OPERATEUR UNAIRE


Soit @ un oprateur unaire. On dfinit : Y operator @(X x); { // corps de la fonction } A l'appel z = @x; // <=> z = operator @(x);

3.2. SYNTAXE DE DEFINITION POUR UNE FONCTION MEMBRE 3.2.1. OPERATEUR BINAIRE
Soit @ un oprateur binaire de la classe X. On dfinit : class X {
Z operator @(Yy); };

Corps de la fonction membre : Z X :: operator @(Yy) { // corps de la fonction }

Conception et programmation oriente objet avec C++

22

LA SURCHAGE DOPERATEURS

A l'appel : Z = x @ y; //<=> z = x.operator @(y);

3.2.2. OPERATEUR UNAIRE


Soit @ un oprateur unaire de la classe X. On dfinit : class X {
Z operator @(); };

Corps de la fonction membre : Z X :: operator @() { // corps de la fonction } A l'appel : Z = @x; // <=> z = x.operator @();

4.

EXERCICE

Pour la classe fraction dfinir les oprateurs : + * - (binaire) - (unaire) / == > < => <= ++ -- += *= -= /= << >>

4.1. OPERATEUR +
class Fraction { Fraction operator +(const Fraction &a) const; }; Fraction Fraction :: operator +(const Fraction &a) const { return Fraction(num * a.den + den * a.num, den * a.den).Simplifie(); }

4.2. OPERATEUR - UNAIRE


class Fraction { Fraction operator -() const; }; Fraction Fraction :: operator -() const { return Fraction(-num, den); }

4.3. OPERATEUR *
class Fraction { Fraction operator *(const Fraction &a) const; }; Fraction Fraction :: operator *(const Fraction &a) const { return Fraction(num * a.num, den * a.den).Simplifie(); }

4.4. OPERATEUR ==
class Fraction { bool operator ==(const Fraction &a) const; };

Conception et programmation oriente objet avec C++

23

LA SURCHAGE DOPERATEURS

bool Fraction :: operator ==(const Fraction &a) const { return (num * a.den == den * a.num); }

4.5. OPERATEUR <


class Fraction { bool operator <(const Fraction &a) const; }; bool Fraction :: operator <(const Fraction &a) const { return num * a.den < den * a.num; }

4.6. OPERATEUR ++
class Fraction { const Fraction & operator ++(); }; const Fraction &Fraction :: operator ++() { num += den; return *this; /*il faut renvoyer l'argument implicite sinon impossible de faire par exemple x2 = ++x1; car ++x1 ne renverrait rien */ }

4.7. OPERATEUR +=
class Fraction { Fraction operator +=(const Fraction &a); }; Fraction Fraction :: operator +=(const Fraction &a) { num = num * a.den + den * a.num; den *= a.den; (*this) = (*this).Simplifie(); return *this; // sinon x3 = x2 += x1; impossible }

4.8. OPERATEUR <<

On ralise une fonction ordinaire. ostream &operator <<(ostream &os, const Fraction &a);
ostream &operator <<(ostream &os, const Fraction &a) { a.Ecrire(os); return os; }

On renvoie os pour pouvoir crire cout << x1 << x2;. On passe le rsultat par rfrence pour permettre dcrire dedans. Si on lomets on renvoie une expression donc pas dcriture possible.

4.9. OPERATEUR >>


istream &operator >>(istream &is, Fraction &a); istream &operator >>(istream &is, Fraction &a) { a = Lire(istream); return is; }

Conception et programmation oriente objet avec C++

24
4.10. AUTRES OPERATEURS

LA SURCHAGE DOPERATEURS

Fraction operator -(const Fraction &a, const Fraction &b); Fraction operator /(const Fraction &a, const Fraction &b); bool operator !=(const Fraction &a, const Fraction &b); bool operator >(const Fraction &a, const Fraction &b); bool operator <=(const Fraction &a, const Fraction &b); bool operator >=(const Fraction &a, const Fraction &b); Fraction operator -(const Fraction &a, const Fraction &b) { return a+(-b); } Fraction operator /(const Fraction &a, const Fraction &b) { return a*(b.Inverse()); } bool operator !=(const Fraction &a, const Fraction &b) { return !(a==b); } bool operator >(const Fraction &a, const Fraction &b) { return b<a; } bool operator <=(const Fraction &a, const Fraction &b) { return !(a>b); }

Conception et programmation oriente objet avec C++

25

LES CONVERSIONS

LES CONVERSIONS
Outre les conversions entre types simples du C, il existe en C++ deux mcanismes pour raliser les conversions entre deux classes diffrentes. Il est possible de raliser des conversions l'aide soit : d'un constructeur. d'un oprateur de conversion.

1.

CONVERSION A L'AIDE D'UN CONSTRUCTEUR

Le constructeur peut servir raliser des conversions d'une classe vers une classe et plus particulirement d'un type simple vers une autre classe. Le constructeur dfinit une conversion ds qu'il existe un constructeur un paramtre. La conversion est ralise depuis le type de l'argument unique ( convertir) vers la classe du constructeur. Exemple : La classe fraction a t muni du constructeur suivant : Fraction::Fraction(const int &a); // constructeur un paramtre Consquence : quelque soit n entier, n est converti en fraction si le contexte l'exige. n est converti en Fraction(n). Exemple : Fraction x1=3; // Fraction x1 = Fraction(3); x1 = x1 + 9; // x1 = x1 + Fraction(9); Le compilateur prend linitiative dappeler le constructeur adapt la situation de faon rendre possible l'instruction.

1.1. APPLICATION
a x + b1y = c1 Soit le problme suivant : rsoudre 1 avec a1, a2, b1, b2 des entiers, c1, c2 des fractions. On obtient la a2 x + b2 y = c 2

fonction suivante :
bool ResoutSystem2x2(const int &a1, const int &b1, const Fraction &c1, const int &a2, const int &b2, const Fraction &c2, Fraction &x, Fraction &y { int d; d = a1 * b2 - a2 * b1; if (d == 0) return false; else { x = (c1 * b2 - c2 * b1) / d; y = (c2 * a1 - c1 * a2) / d; return true; } } Conversions ralises

Avantages des conversions : elles nous vitent d'avoir crire les fonctions qui ralisent : #+%% %+Z % %*Z % Z*% % %/Z % += *= /=
a x + b1y = c1 Les conversions permettent galement d'amliorer la solution dun problme : 1 avec a1, a2, b1, b2, c1, c2 a2 x + b2 y = c 2 des fractions. On obtient les fonctions suivantes :
Fraction Det(const Fraction &a11, const Fraction &a12, const Fraction &a21, const Fraction &a22) { return a11 * a22 - a21 * a12; }

Conception et programmation oriente objet avec C++

26

LES CONVERSIONS

bool ResoutSystem2x2(const Fraction &a1, const Fraction &b1, const Fraction &c1, const Fraction &a2, const Fraction &b2, const Fraction &c2, Fraction &x, Fraction &y) { Fraction d = Det(a1,b1,a2,b2); if (d == 0) return false; else { x = Det(c1,b1,c2,b2)/d; y = Det(a1,c1,a2,c2)/d; return true; } }

1.2. GENERALISATION
Tout constructeur d'une classe X dfinie avec un unique argument de classe Y, dfinit implicitement une conversion de la classe Y vers la classe X. Ds que le contexte l'exige, un Y est converti en X. La nature de la conversion est dfinie par le programmeur car elle est ralise dans le corps du constructeur de X.

2.

CONVERSION A L'AIDE D'UN OPERATEUR DE CONVERSION

Soit une classe X et une classe Y. Il est possible de dfinir une conversion de la classe X vers la classe Y, en dfinissant dans la classe X une fonction membre particulire : un oprateur de conversion vers Y. La syntaxe de dfinition est la suivante:
class X { public: operator Y() const; };

Corps de loperateur de conversion : X :: operator Y() const { return expression dont lvaluation produit une instance de la classe Y; } A prsent, ds que le contexte l'exige, un X est converti en Y l'aide de l'oprateur de conversion. Exemple : on dispose de trois fractions p, q et r et lon voudrait bien rsoudre l'quation px2 + qx + r = 0. On a dj crit la fonction suivante : bool ResoutEquationDegre2 (const double &a, const double &b, const double &c, double &x, double &y, const double &Eps=FLT_EPSILON); Problme: on dispose de fractions p, q et r et la fonction exige des donnes sous format double. La solution est dcrire une conversion de Fraction vers double. Il faut donc modifier la classe Fraction : class Fraction { public : operator double() const; }; Le corps de loprateur : Fraction :: operator double() const { return (double)num / den;// force le transtypage de num car en C entier / entier = entier } A prsent on peut rsoudre lquation, on obtient le programme suivant : main() { Fraction p(8,3), q(11,5), r(-3,4); double x,y; if (ResoutEquationDegre2(p,q,r,x,y)) cout << "les solutions sont " << x << " et " << y << "\n"; else cout << "Pas de solution"; }

Conception et programmation oriente objet avec C++

27

LES CONVERSIONS

Remarque sur les conversions : soient deux classes X et Y, on dsire raliser une conversion de la classe X vers la classe Y. La conversion va tre ralise laide dun constructeur ou dun oprateur ? Si la conversion est ralise laide dun constructeur, ce constructeur est crit dans la classe cible Y. La conversion est ralise sous forme de constructeur dans Y lorsque X nest pas accessible ou bien il est dangereux de le modifier ou bien si X est un type simple. Si la conversion est ralise laide dun oprateur, cet oprateur est membre de la classe source X. La conversion est ralise sous forme doprateur dans la classe X lorsque Y nest pas accessible ou bien il est dangereux de le modifier ou bien si Y est un type simple. X Source oprateur de conversion Conversion Y Destination constructeur un argument de X

3.

CONVERSION EXPLICITE

Comme pour toutes les conversions dfinies en C, il est possible de raliser des conversions forces grce loprateur cast pour les conversions dfinies laide doprateurs ou de constructeurs. Exemple :
Fraction x(8,3); cout << x; cout << (double)x; cout << (Fraction)7;

4.

INCONVENIENTS DES CONVERSIONS

Les conversions implicites peuvent provoquer certaines ambiguts, car laisses linitiative du compilateur, aussi elles obissent certaines rgles dont en voici deux : L'argument implicite dune fonction membre ne peut pas tre obtenu par une conversion implicite. Exemple :
Fraction x(2,3), y; y = 3 + x; // pas possible y = (Fraction)3 + x; // conversion force y = x + 3; // ok

Deux conversions implicites successives ne sont pas ralises.

Soit trois classes X, Y, Z et deux conversions : XY et YZ. Soit x, y, z des instances de X, Y, Z alors : z = x; // ncessite deux conversions implicites : pas ralises z = (Y)x; // ok z = (Z)x; // ok z = (Z)(Y)x; // ok Malgr ces rgles restreignant les conversions implicites il subsiste des problmes graves. Exemple : Fraction Fraction :: operator Somme(const Fraction &x) const { return (num * x.den + den * x.num, den * x.den); // il manque le terme Fraction pour indiquer qu'il sagit d'un constructeur } A la compilation, le compilateur ne retourne pas de message d'erreurs. Il y a conversion implicite du fait de la virgule (oprateur denchanement) et lappel de Fraction (cons int &a); Le langage C++ permet maintenant de faire les conversions avec constructeur de manire explicite uniquement. class Fraction { public: explicit Fraction(const int &a); operator int() const; }; Fraction :: operator int() const { return num / den; }
main() { Fraction x1(8,3), x2; int a, b; a=2;

Conception et programmation oriente objet avec C++

28
x2 x2 x2 x2 x2 = x1 + 7; // refus = x1 + (Fraction)7; // ok = x1 + a; = a+ x1; = x1 + a; x 2 = a
% &' +% " % # &' +# %

LES CONVERSIONS

x1; #

Conception et programmation oriente objet avec C++

29

EXEMPLE COMPLET DE CLASSE

EXEMPLE COMPLET DE CLASSE


1. RAPPEL SUR LES CHAINES DE CARACTERES EN C
Elles sont ralises sous formes de tableaux. Les tableaux contenant des caractres comportent un caractre spcial de terminaison \0 (octet dont tous les bits sont 0).
main() Mmoire { char t[6]; 0 1 2 3 4 5 t[0]=S; t[1]=a; S a l u t t \0 t[2]=l; t[3]=u; n 5 t[4]=t; t[5]=\0; cout << t; s int n = strlen(t); char *s; // case mmoire habilit contenir une adresse physique dune case contenant un caractre s = t; // t expression littrale de ladresse physique qui pointe sur t cout << s[0]; //renvoie la premire lettre cout << *s; // dsigne le contenu de la case pointe par s : *s == s[0] t = s; // refus
Mmoire

s = pif; n = strlen(s); // ok char c; c = s; // refuse char *s1, *s2, *r; s1 = pif; s2 = le chien; int u1, u2; u1 = strlen(s1); u2 = strlen(s2); r = new char[1 + u1 + u2]; strcpy(r, s1); // r est la destination, s1 est la source

0 s p

1 i

2 f

3 \0

strcat(r, s2); // r doit contenir au minimum \0, concatne une chane dan une chane ayant dj des caractres }
Mmoire 0 s1 p 0 s1 _ 0 r p 1 i 1 l 1 i 2 f 2 e 2 f 3 \0 3 _ 3 _ 4 c 4 l 5 h 5 e 6 i 6 _ 7 e 7 c 8 n 8 h 9 \0 9 i 10 e 11 n 12 \0

2.

EXERCICE

Crer une classe Chaine permettant de grer les chaines de caracteres en C++. Cette classe doit: Etre compatible avec char, char*. Etre sure d'emploi. Etre simple d'utilisation. Utiliser l'existant sur le type char*.

Conception et programmation oriente objet avec C++

30
La classe comportera: Un ou plusieurs constructeurs Une fonction longueur Faire la surcharge d'operateur : o == o < o <= o + (concatenation) o << o >>

EXEMPLE COMPLET DE CLASSE

L'allocation dynamique s'effectue avec l'oprateur new.

3.

LA CLASSE CHAINE

#define DEBUG class Chaine { char *t; // pour linstant il ny a pas de tableau (pas de caractres), le tableau sera allou en cours dexcution void Alloue(const Naturel &n); //alloue n caractres public : Chaine (); // cre la chane vide Chaine (const char *s); Chaine (const char &c); Chaine (const Chaine &ch); // constructeur de copie Chaine (const Naturel &n, const char &c); // cre une chane contenant n fois le caractre c ~ Chaine(); // ~ est le symbole du destructeur Naturel Longueur() const; Chaine operator +(const Chaine & ch) const; const Chaine &operator =(const Chaine &ch); // le rsultat est pass par rfrence char operator [](const Naturel &i) const; // renvoie une valeur, sert consulter /* 0 i (*this).Longueur() -1 */ char &operator [](const Naturel &i); // renvoie un objet, sert modifier bool operator <=(const Chaine &ch) const; void Ecrire(ostream &os) const; }; ostream &operator <<(ostream &os,const Chaine &ch); istream &operator >>(istream &is, Chaine &ch);

En bleu sont les fonctions membres ncessaires pour raliser une classe avec allocation dynamique. Les fonctions prcdes du signe effectue une allocation dynamiquement.
main { char c; char p[10]; char *s; //plus souple demploi que le tableau s = salut; Chaine ch1(s); cout << sizeof(Chaine); // taille en octets de nimporte quelle chane n = ch1.Longueur(); c = M; Chaine ch2(c), ch3; Chaine ch4(pif), ch5( le chien), ch6; ch6 = ch4 + ch5; // ch6 = ch4.operator+(ch5); }
Mmoire 0 p 0 s ch1 c ch2 t t M 0 M 0 ch3 t \0 1 \0 s 1 a 2 l 3 u 4 t 5 \0 1 2 3 4 5 6 7 8 9

Conception et programmation oriente objet avec C++

31
4. FONCTIONS MEMBRES
4.1. FONCTION PRIVEE ALLOUE

EXEMPLE COMPLET DE CLASSE

void Chaine :: Alloue(const Naturel &n) { t = new char[n]; if (t == NULL) Erreur(Chaine:: Alloue(n): mmoire sature); }

4.2. CONSTRUCTEUR CHAINE(CONST CHAR *S)


Chaine :: Chaine(const char *s) { t = new char[1 + strlen(s)]; strcpy(t, s); }

Optimisation 1 : il est possible quil ny a plus de place dans le tas mmoire do le test (allocation dynamique de mmoire). Chaine :: Chaine(const char *s) { t = new char[1 + strlen(s)]; if (t == Null) Erreur(Chaine:: Chaine(s) : mmoire sature); strcpy(t, s); } Optimisation 2 : utilisation de la fonction prive Alloue(). Chaine :: Chaine(const char *s) { Alloue(1 + strlen(s)); strcpy(t, s); }

4.3. CONSTRUCTEUR CHAINE(CONST CHAR &CH)


Chaine :: Chaine(const Chaine &ch) { t = new char[1 + strlen(ch.t)]; strcpy(t, ch.t); cout << Appel au constructeur de copie; } Chaine :: Chaine(const Chaine &ch) { Alloue(1 + strlen(ch.t)); strcpy(t, ch.t); cout << Appel au constructeur de copie; }

4.4. CONSTRUCTEUR CHAINE(CONST CHAR &C)


Chaine :: Chaine (const char &c) { t = new char[2]; *t = c; // quivaut t[0] = c; *(t + 1) = \0; // quivaut t[1] = \0; } Chaine :: Chaine (const char &c) { Alloue(2); *t = c; // quivaut t[0] = c; *(t + 1) = \0; // quivaut t[1] = \0; }

4.5. CONSTRUCTEUR CHAINE()


Chaine :: Chaine () // cre la chane vide

Conception et programmation oriente objet avec C++

32
{ t = new char [1]; t[0] = \0; } Chaine :: Chaine () // cre la chane vide { Alloue(1); t[0] = \0; }

EXEMPLE COMPLET DE CLASSE

4.6. CONSTRUCTEUR CHAINE (CONST NATUREL &N, CONST CHAR &C)


Chaine (const Naturel &n, const char &c) // cre une chane contenant n fois le caractre c {}

4.7. DESTRUCTEUR
Chaine :: ~ Chaine() { delete []t; // cout << appel au destructeur; } Le systme vrifie quil y a un destructeur dans la classe chaque fois quune instance est restitue et y fait appel

4.8. OPRATEUR +
Chaine :: Chaine operator +(const Chaine & ch) const { Chaine r; r.t = new char[1 + strln(t) + strlen(ch.t)]; strcpy(r.t, t); strcat(r.t, ch.t); return r; Mmoire }
0 1 i 1 l 2 f 2 e 3 \0 3 _ 4 c 5 h 6 i 7 e 8 n 9 \0

main() { Chaine ch4(pif); Chaine ch5( le chien); Chaine ch6; ch6 = ch4 + ch5; // ch6 = ch4.operator+(ch5); }

ch4

p 0

ch5

_ 0

ch6

\0 0

0 p

1 i

2 f

3 _

4 l

5 e

6 _

7 c

8 h

9 i

10 e

11 n

12 \0

\0

Pour ne pas laisser traner en mmoire le tableau vide dinitialisation de r on rcrit la fonction de la manire suivante :
Chaine Chaine :: operator +(const Chaine & ch) const { Chaine r(strlen(t) + strlen(ch.t), ); strcpy(r.t, t); strcat(r.t, ch.t); return r; }

4.9. OPRATEUR =
const Chaine &Chaine :: operator =(const Chaine &ch) // le rsultat est pass par rfrence { if (this != &ch) // evite ch = ch { delete []t; Alloue(1 + strlen(ch.t)); // t = new char[1 + strlen(ch.t)]; strcpy(t, ch.t); } return *this;

Conception et programmation oriente objet avec C++

33

EXEMPLE COMPLET DE CLASSE


Mmoire ch1 ch2 ch2 t t t b c b o i o n a n j o j o \0 o u r \0 u r \0

} main() { Chaine ch1(bonjour), ch2(ciao); ch2 = ch1; // quivaut ch2.operator = (ch1); }

4.10. OPRATEUR []

main() { Chaine ch1(pif), ch2(pouf), ch3; char c; c = ch1[0]; // quivaut c= ch1.operator[](0); c = ch1[18];; // quivaut c= ch1.operator[](18); } char Chaine :: operator [](const Naturel &i) const /* renvoie une valeur, sert consulter, 0 i (*this).Longueur() -1 */ { #ifdef DEBUG if (i >= strlen(t)) Erreur(Chaine :: operator[](i) : llment i nest pas dfini); #endif return t[i]; } Test coteux lexcution cause de la boucle de parcours sur la chane de caractres : phases de dbugage ???????? certains tests, supprims aprs finalisation du programme. Le test sera ignor la compilation quand linstruction #define DEBUG sera mise en commentaire. main() { Chaine ch1(pif), ch2(pouf), ch3; char c; ch1[1] = c; // quivaut ch1.operator[](1) = c; }

Il ny a pas de const la fin du prototype de la fonction, on peut modifier largument implicite. Cest un objet et on va le modifier. On renvoie un objet : on a le droit de le renvoyer par rfrence.
char &Chaine :: operator [](const Naturel &i) /* renvoie un objet, sert modifier */ { #ifdef DEBUG if (i >= strlen(t)) Erreur(Chaine :: dfini); #endif return t[i]; }

operator[](i) :

llment

nest

pas

4.11. OPRATEUR <=


main() { Chaine ch1(pif), ch2(pouf), ch3; char c; bool ok; ok = (ch1 <= ch2); // quivaut ok = ch1.operator[(1) = c;] } bool Chaine :: operator <=(const Chaine &ch) const { return strcmp(t, ch.t) <= 0; }

4.12. FONCTION ECRIRE()


void Chaine :: Ecrire(ostream &os) const {

Conception et programmation oriente objet avec C++

34
os << t; }

EXEMPLE COMPLET DE CLASSE

4.13. OPRATEUR <<


main() { Chaine ch1(pif); cout << ch1; // quivaut cout.operator<<(ch1); }

On ralise une fonction ordinaire car on ne modifie pas la classe ostream.


ostream &operator <<(ostream &os,const Chaine &ch) { ch.Ecrire(os); return os; }

4.14. OPRATEUR >>


main() { Chaine ch3; cin << ch1; // quivaut cin.operator<<(ch3); } istream &operator >>(istream &is, Chaine &ch) { static char s[1024]; is.getline(s, 1023, ); ch = Chaine(s); return is; }

istream &is permet dcrire cin >> ch1 >> ch2.

4.15. FONCTION LONGUEUR()


Naturel Chaine :: Longueur() const { return (Naturel) strlen(t); }

Conception et programmation oriente objet avec C++

35

LHERITAGE ET LES CLASSES DERIVEES

LHERITAGE ET LES CLASSES DERIVEES


1. INTRODUCTION
Soit une classe X dfinie comme suit : classe X { int a; double b;
public : X(int n,double x); void Ecrire() const; };

Et soit la classe Y dfinie comme suit : class Y : public X // la classe Y drive de la classe X { char c[10];
public : Y(); void Ecrire() const; };

Cette dfinition fait de Y une classe drive de la classe X. On dit que : Y hrite de X. Y est une sous classe de X. X est la classe mre de Y ). X est la superclasse de Y. X est la classe de base de Y. Cette relation est souvent note par le diagramme:

Lintret de cette dfintion est que toute instance de la classe Y est une instance de la classe X, autrement dit : {ensemble des instances de Y} {ensemble des instances de X}
Ensemble des instances de Y Ensemble des instances de X

Soit y une instance de la classe Y, selon le contexte, y est considre comme instance de Y ou de X. Par contre si x est une instance de X, x nest jamais considre comme instance de Y car Y X et X Y . On peut considrer que les instances de T sont des instances particulires, spcialises de la classe X. On peut donc considrer que la relation dhriyage est une relation de spcialisation, du gnral au particulier.

2.

HERITAGE ET CONVERSION

Lorsque y est vu comme une instance de X seuls sont considres ses membres (donnes et fonctions) relatives la classe X, c'est--dire :

Conception et programmation oriente objet avec C++

36

LHERITAGE ET LES CLASSES DERIVEES


y a b X() Ecrire() y a b X() Ecrire() c Y() Ecrire()

Membres de y lorsque y est vu comme instance de X

Membres de y lorsque y est vu comme instance de X. Concrtement : taille(Y) = taille(X) + 10 (octets du tableau c)

Lorsquun membre a le mme nom dans la classe drive et la classe de base, comme cest le cas ici pour la fonction Ecrire(), la dfinition de la classe drive cache celle de la classe de base. Rsum : lorsque y est considr comme instance de la classe X, toutes les dfinitions relatives Y sont ignores (mais toujours prsentes en mmoires en ce qui concerne les membres donnes).

3.

PROTECTION DES MEMBRES ET HERITAGE

Les fonctions membres de la classe Y nont pas accs la partie prive de la classe X sinon pour contourner le mcanisme de protection il suffirait de raliser un hritage. Si une classe dcide dautoriser ses classes drives daccder certains de ses membres, elle doit dclarer ceux-ci protgs (mot cl protected). Rsum des mcanismes de protection : Si un membre de X est dclar priv (private) seules les fonctions membres de X y ont accs. Si un membre de X est dclar protg (protected) les fonctions membres de X et toutes classes drives de X y ont accs. Si un membre de X est dclar public (public) toutes fonctions y ont accs. Exemple 1 : gestion du personnel dune entreprise. On dfinit une classe Employ : Nom. Echelon. Nombre dheures travailles dans le service. Les oprations souhaites pour un employ : Constructeur. Calcul de salaire.
class Employe { Chaine nom; int echelon; double nbheures; public : Employe(const Chaine &nomEmploye, const int &nbheuresMois); double Salaire(const double &tarihoraire) const; void Ecrire(ostream &os) const; void EcrireNom( ostream &os) const; &echelonEmploye, const double

};

Un chef de service est un employ responsable dun service, on lui associe le chiffre daffaires de ce service. Il est clair quun chef de service est un employ particulier, spcialis : {ensemble des chefs} {ensemble des employs} do la classe Chef hritant de la classe Employe. Informations supplmentaires : Nom du service. CA du service. Consulter le Ca.

Employe

Hrite de

Chef

Conception et programmation oriente objet avec C++

37
On obtient la classe suivante : class Chef : public Employe { Chaine nomService;

LHERITAGE ET LES CLASSES DERIVEES

public : Chef(const Chaine &nomChef, const int &echeleonChef, const double &nbheuresMois, const Chaine &nomserviceChef, const double &chiffreAffaires); Chef(const Employe &employe, const Chaine &nomserviceChef, const double &chiffreAffaires); double Chiffre() const; double Salaire(const double &tarifhoraire) const; void Ecrire(ostream &os) const; }; Chef :: Chef(const Chaine &nomChef, const int &echeleonChef, const double &nbheuresMois, const Chaine &nomserviceChef, const double &chiffreAffaires) : Employe(nomChef, echelonChef, nbheuresMois) { nomservice = nomserviceChef; CA = chiffreAffaires; } Chef :: Chef(const Employe &employe, &chiffreAffaires) : Employe(employe) { nomservice = nomserviceChef; CA = chiffreAffaires; } double Chef :: Chiffre() const { return CA; } double Chef :: Salaire(const double &tarifhoraire) const { return 0.01 * CA + Employe :: Salaire(tarifhoraire); } void Chef:: Ecrire(ostream &os) const { Employe:: Ecrire(os); os << service << nomservice << chiffre daffaires = << CA; } main() { Employe e1(_,_,_); Chef f1(_,_,_); e1.Ecrire(cout); f1.Ecrire(cout); f1.EcrireNom(cout); cout << e1.Chiffre(); // pas de fonction chiffre dans la classe Employe : refus cout << f1.Chiffre(); e1 = f1; // converti le chef en employ et zappe les informations supplmentaires f1 = e1; // refus car manque dinformations ((Employe)f1).Ecrice(cout); // pour forcer lutilisation de la fonction de Employe f1.Employe :: Ecrire(cout); // comme ci-dessus } const Chaine &nomserviceChef, const double

Conception et programmation oriente objet avec C++

38

LHERITAGE ET LES CLASSES DERIVEES

La relation dhritage peut tre enrichie par lajout de nouvelles classes. On obtient une hirarchie de classe ou graphe dhritage. Plus on remonte dans cette hirarchie, plus les classes deviennent gnrales. Plus on descend dans cette hirarchie plus les classes deviennent spcialises. Les fonctions membres, donnes membres communes plusieurs classes migrent vers la classe de base. Lintret est dliminer les redondances dinformations, de code. La classe de base permet de factoriser les notions communes plusieurs classes.

Conception et programmation oriente objet avec C++

39

LES FONCTIONS VIRTUELLES

LES FONCTIONS VIRTUELLES

Conception et programmation oriente objet avec C++

40

LES CLASSES ABSTRAITES

LES CLASSES ABSTRAITES

Conception et programmation oriente objet avec C++

41

LES PATRONS (TEMPLATES)LES CLASSES ABSTRAITES

LES PATRONS (TEMPLATES)


1. INTRODUCTION
On veut calculer le maximum de deux entiers. Fichier entier.h int Max(const int &a, const int &b); Fichier entiers.cpp int Max(const int &a, const int &b) { if (a >b) return a; else return b; } Maintenant on veut raliser la mme fonction avec des rels. Fichier reels.h double Max(const double &a, const double &b); Fichier reels.cpp double Max(const double &a, const double &b) { if (a > b) return a; else return b; } On a besoin ensuite de manipuler des fractions avec le mme type de fonction. Fichier fractions.h Fraction Max(const Fraction &a, const Fraction &b); Fichier fractions.cpp Fraction Max(const Fraction &a, const Fraction &b) { if (a > b) return a; else return b; }
#include entiers.h #include reels.h #include fractions.h main() { int x, y, z; x = 3; y = 5; z = Max(x,y); double r1, r2, r3; r1 = 3.5; r2 = 7.8; r3 = Max(r1,r2); Fraction x1(2,3), x2(1,4), x3; x3 = Max(x1,x2);

On remplace le type int pour les entiers par un type quelconque pour faire gnrique. On fait abstraction des fichiers rels et fractions. Fichier entier.h Typedef int T; T Max(const T &a, const T &b); Fichier entiers.cpp T Max(const T &a, const T &b)

Conception et programmation oriente objet avec C++

42
{ if (a >b) return a; else return b;

LES PATRONS (TEMPLATES)LES CLASSES ABSTRAITES

} #include entiers.h /*#include reels.h #include fractions.h*/ main() { int x, y, z; x = 3; y = 5; z = Max(x,y); /*double r1, r2, r3; r1 = 3.5; r2 = 7.8; r3 = Max(r1,r2); Fraction x1(2,3), x2(1,4), x3; x3 = Max(x1,x2);*/

Le programme est test et valid, ensuite pour les rels on garde le tout en remplacant le typedef int T par un double T. On dplace dans le programme principal les commentaires. On refait de mme pour les fractions. On na alors quune seule possibillit dutilisation de la fonction la fois. Le but est le paramtrage de la fonction par le type : cest le mcanisme du modle de fonctions

2.

MODELE DE FONCTION

Fichier modeles.h (dclaration du modle) template <class T> T Max(const T &a, const T &b); Fichier modeles.cpp (dfinition du modle) template <class T> // mettre devant chaque modle de fonction T Max (cont T &a, const T &b) { if (a > b) return a; else return b; } Le modle ne se compile pas. Suivant les types de compilateur, la compilation et ldition des liens sera diffrente. Fichier modeles.h #ifndef MODELES.H #define MODELES.H
template <class T> T Max(const T &a, const T &b); #include modeles.cpp #endif

Fichier modeles.cpp template <class T> // mettre devant chaque modle de fonction T Max (cont T &a, const T &b) { if (a > b) return a; else return b; } Avec C++ Builder le corps de la mthode est mettre dans le fichier denttes. On compile le programme principal.

3.

MODELE DE CLASSE

Supposons que dans un certain contexte de programmation, on ait besoin de la notion de pile de nombres entiers. La classe Pile obtenue, doit tre munie des fonctions suivantes : Insrer dans la pile.

Conception et programmation oriente objet avec C++

43

LES PATRONS (TEMPLATES)LES CLASSES ABSTRAITES


Retirer de la pile. La pile est-elle vide. Crer une pile vide. Mmoire p m p p1 -2 4 -2 -2 7 7 4 4 8 7 3 4

#include pile.h main() { Pile p; int m; Pile p1; p.Inserer(-2); p.Inserer(7); p.Inserer(3); p.Inserer(4); m.Retirer(); p1 = p.Insertion(8); }

Fichier pile.h #define MAXPILE 100 // arbitriare #define DEBUG


class Pile // dfinit une pile dentiers (LIFO) { int t[MAXPILE]; // t[0] t[p] sont les cases occupes int s; // -1 s MAXPILE-1 indice de la dernire case occupe public : Pile(); // cre une pile vide boo Estvide()const; void Inserer(const int &a); // insre llment x en tte, modifie la pile int Retirer(); // retire llment de tte et le renvoie, modifie laa pile Pile Insertion(const int &a) const; // insertion en tte, ne modife pas la pile argument implicite };

Fichier pile.cpp Pile :: Pile() { s = -1; }


void Pile :: Inserer(const int &a) { #ifndef DEBUG if (s = MAXPILE 1) Erreur(Pile :: Inserer(a) : pile pleine); #endif t[++s] = a; // incrmente dabord s et utilise la valeur de s //quivalent ++s; t[s] = a; } bool Pile :: Estvide() const { return (s == -1); // teste la valeur de s gale -1 } int Pile :: Retirer() { #ifndef DEBUG If (s == -1) Erreur(Pile:: Retirer(): pile vide); #endif return t[s--]; // renvoie t[s]et dcrmente ensuite }

Conception et programmation oriente objet avec C++

44

LES PATRONS (TEMPLATES)LES CLASSES ABSTRAITES

Pile Pile :: Insertion(const int &a) const { Pile r(*this); // copie physique r.Inserer(a); return r; }

Pour faire un template pour utiliser avec des doubles, fractions et autres on remplace les int par un type gnrique T associ au typedef correspondant. Comme prcdemment la limitation de cette technique est lutilisation dun seul type de pile dans le programme principal. Do la ncessit de crer un modle de classe. Pile.h template <class T, int n> #define DEBUG
class Pile // dfinit une pile dentiers (LIFO) { T t[n]; // t[0] t[p] sont les cases occupes int s; // -1 s n-1 indice de la dernire case occupe public : Pile(); // cre une pile vide boo Estvide()const; void Inserer(const T &a); // insre llment x en tte, modifie la pile T Retirer(); // retire llment de tte et le renvoie, modifie laa pile Pile<T,n> Insertion(const T &a) const; // insertion en tte, ne modife pas la pile argument implicite };

Fichier pile.cpp template <class T, int n> Pile<T,n> :: Pile() { s = -1; }


template <class T, int n> void Pile<T,n> :: Inserer(const T &a) { #ifndef DEBUG if (s = n 1) Erreur(Pile :: Inserer(a) : pile pleine); #endif t[++s] = a; // incrmente dabord s et utilise la valeur de s //quivalent ++s; t[s] = a; } template <class T, int n> bool Pile<T,n> :: Estvide() const { return (s == -1); // teste la valeur de s gale -1 } template <class T, int n> T Pile<T,n> :: Retirer() { #ifndef DEBUG If (s == -1) Erreur(Pile:: Retirer(): pile vide); #endif return t[s--]; // renvoie t[s]et dcrmente ensuite } template <class T, int n> Pile<T,n> Pile<T,n> :: Insertion(const T &a) const { Pile<T,n> r(*this); // copie physique r.Inserer(a); return r; }

Conception et programmation oriente objet avec C++

45

LES EXCEPTIONS

LES EXCEPTIONS

Conception et programmation oriente objet avec C++

PROJET ANNUEL

Conception et programmation oriente objet avec C++

47

PROJET ANNUEL DE PROGRAMMATION ORIENTEE OBJET EN LANGAGE C++

PROJET ANNUEL DE PROGRAMMATION ORIENTEE OBJET EN LANGAGE C++


1. ORGANISATION DU TRAVAIL
Les auditeurs peuvent se grouper par binmes pour raliser le travail. Un binme sera le mme pour les trois problmes.

2.

TRAVAIL DEMANDE

Raliser en C++, toutes les classes impliques dans la rsolution des problmes demands. Date de remise : au plus tard le lundi 13 juin 2005.

3.

MODALITES DE LA SOUTENANCE

Les soutenances seront organises dans la semaine qui suit la semaine de remise des projets. Elles auront lieu dans mon bureau (E 113. 1er tage lUFR MIM) ou en salle de TP lIUT. Une soutenance dure environ 40 minutes. Si vous avez ralis le projet sur un ordinateur portable, celui-ci sera bienvenu. La note de projet tiendra compte du bon fonctionnement des programmes demands et de la qualit de la programmation (la qualit de lanalyse et la rigueur de programmation seront examines).

4.

SUJET
4.1. PROBLEME 1. GESTION DE FICHIERS GENERIQUES

Le but est de mettre en uvre une classe fichier de X o X peut tre nimporte quel type ou nimporte quelle classe. Par lintermdiaire de cette classe il doit donc tre possible de sauvegarder sur disque nimporte quelle suite finie (liste, tableau, etc) de donnes quelque soit leur type. Vous ne pouvez donc faire aucune hypothse sur X. La nature de X sera prcise dans le programme principal. Bien entendu, par lintermdiaire de cette mme classe, il doit tre possible de restaurer les donnes sauvegardes sans perte dinformation. Vous pouvez supposer que la classe (ou le type) X fournit les deux fonctions non membres suivantes : char * ConversionChaine(const X& x); void ChaineConversion(char * c, X& x); //Donne : c, rsultat : x

La premire fonction permet de convertir une instance de la classe X au format chane de caractre. La seconde permet de raliser la conversion rciproque et donc de restaurer intacte toute donne x traduite en chane par la premire.

4.1.1. CAHIER DES CHARGES DE LA CLASSE FICHIER DE X


La classe fichier de X doit permettre les oprations suivantes : Ouverture en lecture uniquement a partir dun fichier physique disque. Ouverture en criture uniquement vers un fichier physique disque. Oprateur dcriture << en fin de fichier dun nouvel lment sur le fichier. Uniquement disponible si le fichier a t ouvert en criture. Oprateur de lecture >> du prochain lment sur le fichier. Uniquement disponible si le fichier a t ouvert en lecture. Oprateur [] daccs direct en lecture a llment n i. Fonction indiquant si le fichier est vide. Fonction indiquant la taille du fichier (unit : le nombre dlments). Noubliez pas, en outre, de munir cette classe de toute opration ncessaire son bon fonctionnement.

4.1.2. GESTION DES ERREURS


Les erreurs dentre-sortie ou autres doivent toutes tre gres : le programmeur utilisant la classe de fichiers de X doit pouvoir le faire de faon sre. Le minimum que doivent donc faire vos fonctions, en matire de gestion derreur, est de signaler au programme appelant le problme rencontr si elles ne peuvent pas traiter elles mme ce dernier. Ce cahier des charges nest pas exhaustif, vous pouvez ltendre, il en sera tenu compte le cas chant.

4.2. PROBLEME 2 : GESTION DENSEMBLES GENERIQUES


Le but est de fournir au programmeur une classe gnrique densemble mathmatique munie des oprations classiques de lalgbre de Boole. Notons cette classe Ensemble de X. Cette classe permet de reprsenter des ensembles

Conception et programmation oriente objet avec C++

48

PROJET ANNUEL DE PROGRAMMATION ORIENTEE OBJET EN LANGAGE C++

dinstances de X o X peut tre nimporte quel type ou nimporte quelle classe. La nature de X sera prcise dans le programme principal. Rappel : proprit dun ensemble : Un ensemble ne contient pas de doublon; cest dire quun lment nest jamais prsent en plus dun exemplaire.

4.2.1. CAHIER DES CHARGES DE LA CLASSE ENSEMBLE DE X :


La classe Ensemble de X doit permettre de raliser les oprations suivantes : 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12) 13) 14) Cration vide. Insertion dun nouvel lment (sans crer de doublons). Calcul de la taille. Indiquer si une valeur quelconque appartient lensemble. Retrait dun lment (le premier par exemple). Accs en lecture llment n i ( laide de loprateur []). Opration runion ensembliste (oprateur + pour raliser des instructions de la forme e1 = e2+e3;). Opration intersection ensembliste (oprateur *). Oprateur +=. Oprateur daffichage <<. Indiquer si un ensemble est inclus (au sens large) dans un autre (oprateur <=). Indiquer si deux ensembles sont gaux (oprateur ==). Rappel : (e1 == e2) ((e1 e2) et (e2 e1)). Oprateur de diffrence ensembliste (oprateur -). Construire lensemble des sous ensembles dun ensemble.

Les oprations 7 14 doivent tre non membres. Noubliez pas de munir la classe de toute opration ncessaire son bon fonctionnement.

4.3. PROBLEME 3. DERIVATION FORMELLE


Le but est de reprsenter en machine une expression arithmtique reprsentant une fonction mathmatique et de procder sur cette fonction quelques oprations. La fonction est une fonction dune variable relle et valeurs relles. Elle peut contenir les oprateurs + - * / et ^ (exposant) et les fonctions sin, cos et ln et loprateur unaire. Les oprandes peuvent tre soit des constantes numriques, soit la variable (unique).
Les oprations souhaites sur une telle expression sont :

Evaluation pour une valeur donne la variable. Obtention de lexpression de la drive formelle. Simplification de lexpression (opration essentielle pour la drivation). Affichage sur la sortie standard. Ralisation dun duplicata. Toute opration ncessaire au bon fonctionnement dune expression.

Conception et programmation oriente objet avec C++

ANNEXES

Conception et programmation oriente objet avec C++

50

PROGRAMMES

PROGRAMMES
Note de lauteur : les diffrents programmes ont t tests et valids en utilisant lIDE Dev-C++ 5.0 beta 9.2 (4.9.9.2) avec Mingw/GCC 3.4.2 que vous trouverez sur http://www.bloodshed.net/dev/devcpp.html , voir galement http://www.bloodshed.net/.

1.

ENTIERS.H

#ifndef ENTIERSH #define ENTIERSH /*definit le type naturel a partir d'entiers non signes*/ typedef unsigned int Naturel; Naturel Pgcd1(const Naturel &a, const Naturel &b); /*calcule le pgcd de a et b, hypothse a >= 1 b >= 1*/ Naturel Pgcd(const int &a, const int &b); /*on suppose (a,b) <> (0,0)*/ #endif

2.

ENTIERS.CPP

#include <stdlib.h> #include "entiers.h" Naturel Pgcd1(const Naturel &a, const Naturel &b) /*calcule le pgcd de a et b, hypothse a >= 1 b >= 1, Version rcursive */ { if (a == b) return a; // cas trivial else if (a > b) return Pgcd1(a - b,b); // cas gnral else /*a < b*/ return Pgcd1(a,b - a); // avec un sous problme } Naturel Pgcd(const int &a, const int &b) /*on suppose (a,b) <> (0,0)*/ { if (a == 0) return abs(b); else /*a <> 0*/ { if (b == 0) return abs(a); else /* a <> 0 et b <> 0*/ return Pgcd1(abs(a),abs(b)); } }

3.

ERREURS.H

#ifndef ERREURSH #define ERREURSH /*definition de la fonction d'erreur*/ /*envoie le message sur le fichier d'erreur standard puis arrete le programme*/ void Erreur(char * message); #endif

4.

ERREURS.CPP

#include <iostream> #include "erreurs.h" using namespace std; /*definition de la fonction d'erreur*/ /*envoie le message sur le fichier d'erreur standard puis arrete le programme*/ void Erreur(char * message) { cerr << "\n\n Erreur!" << message << endl;

Conception et programmation oriente objet avec C++

51
exit(0); }

PROGRAMMES

5.

FRACTIONS.H

#ifndef FRACTIONSH #define FRACTIONSH using namespace std; //------------------------- classe Fraction --------------------------------------class Fraction { /*par dfaut priv*/ int num; // numrateur Naturel den; // dnominateur >= 1 public: /*dclaration de ce qui est public jusqu' nouvel ordre*/ /*------------Fonctions membres---------------------------*/ Fraction(); // constructeur cre 0 / 1 Fraction(const int &a); // constructeur cre a / 1 Fraction(const int &a, const Naturel &b); // constructeur cre a/b on suppose b <> 0 Fraction Somme(const Fraction &a) const; /*additionne la fraction passee en reference a la fraction implicite*/ //le dernier const signifie que la fonction membre ne modifie pas l'argument implicite Fraction Produit(const Fraction &a) const; /*fait le produit de la fraction passee en reference a la fraction implicite*/ Fraction Oppose() const; // renvoie l'oppos de l'argument implicite Fraction Inverse() const; // renvoie l'inverse de l'argument implicite Fraction Simplifie() const; /*simplifie une fraction*/ bool Est_egal(const Fraction &a) const; /*teste l'egalite de la fraction passee en reference avec la fraction implicite*/ void Ecrire(ostream &os) const; // affiche sur la sortie standard la fraction implicite Fraction operator +(const Fraction &a) const; /*surcharge d'oprateur additionne la fraction passee en reference a la fraction implicite*/ Fraction operator -() const; /*surcharge d'oprateur renvoie la fraction opposee de la fraction implicite*/ Fraction operator *(const Fraction &a) const; /*surcharge d'oprateur fait le produit de la fraction passee en reference a la fraction implicite*/ bool operator ==(const Fraction &a) const; /*surcharge d'oprateur teste l'egalite de la fraction passee en reference avec la fraction implicite*/ bool operator <(const Fraction &a) const; /*surcharge d'oprateur teste l'inferiorite de la fraction passee en reference a la fraction implicite*/ const Fraction & operator ++(); /*surcharge d'operateur incrmentation la fonction est constante pour empecher par exemple ++x1 = x2*/ Fraction operator +=(const Fraction &a); /*surcharge d'operateur effectue a = a+b*/ }; // ne pas oublier le; /*-----------------Declaration des fonctions ordinaires---------------------*/ Fraction Difference(const Fraction &a, const Fraction &b); /*fait la difference de deux fractions passees en parametre*/ Fraction Quotient(const Fraction &a, const Fraction &b); /*fait la division de deux fractions passees en parametre*/ Fraction Lire(istream &is); /*saisie d'une fraction depuis l'entre standard*/ ostream &operator <<(ostream &os, const Fraction &a);

Conception et programmation oriente objet avec C++

52

PROGRAMMES

/*surcharge d'oprateur crit sur le flux de sortie la fraction*/ istream &operator >>(istream &is, Fraction &a); /*surcharge d'oprateur saisie sur le flux d'entre la fraction*/ Fraction operator -(const Fraction &a, const Fraction &b); /*surcharge d'oprateur fait la difference de deux fractions passees en parametre*/ Fraction operator /(const Fraction &a, const Fraction &b); /*surcharge d'oprateur fait la division de deux fractions passees en parametre*/ bool operator !=(const Fraction &a, const Fraction &b); /*surcharge d'oprateur teste la non egalite de deux fractions passees en parametre*/ bool operator >(const Fraction &a, const Fraction &b); /*surcharge d'oprateur teste la superiorite de deux fractions passees en parametre*/ bool operator <=(const Fraction &a, const Fraction &b); /*teste l'inferiorite ou egalite de deux fractions passees en parametre*/ bool operator >=(const Fraction &a, const Fraction &b); /*teste la superiorite ou egalite de deux fractions passees en parametre*/ #endif

6.

FRACTIONS.CPP
<iostream> "entiers.h" "erreurs.h" "fractions.h"

#include #include #include #include

//--------------- implementation de la classe Fraction -----------------------/*referencement des fonctions membres a sa classe d'origine*/ /*les constructeurs portent le mme nom que la classe*/ Fraction :: Fraction() // constructeur cre 0 / 1 { num = 0 ; den = 1 ; } Fraction :: Fraction(const int &a) // constructeur cre a / 1 { num = a ; den = 1 ; } Fraction :: Fraction(const int &a, const Naturel &b) /* constructeur cre a/b on suppose b <> 0*/ { if (b == 0) Erreur("Fraction :: Fraction(a,b) : b == 0") ; if (b > 0) { num =a; den = b; } else /*b < 0*/ { num = - a; den = (Naturel)(-b); } } Fraction Fraction :: Somme(const Fraction &a) const /*additionne la fraction passee en reference a la fraction implicite*/ { return Fraction(num * a.den + den * a.num, den * a.den).Simplifie(); } Fraction Fraction :: Produit(const Fraction &a) const /*fait le produit de la fraction passee en reference a la fraction implicite*/ { return Fraction(num * a.num, den * a.den).Simplifie(); } Fraction Fraction :: Oppose() const // renvoie l'oppos de l'argument implicite

Conception et programmation oriente objet avec C++

53
//renvoie -(*this) { return Fraction(-num, den) ; }

PROGRAMMES

Fraction Fraction :: Inverse() const // renvoie l'inverse de l'argument implicite { return Fraction(den,num); } Fraction Fraction :: Simplifie() const /*simplifie une fraction*/ { Naturel p ; p = Pgcd(num,den) ; return Fraction(num / p,den / p); } bool Fraction :: Est_egal(const Fraction &a) const /*teste l'egalite de la fraction passee en reference avec la fraction implicite*/ { return num * a.den == den * a.num ; } void Fraction :: Ecrire(ostream &os) const // affiche sur la sortie standard la fraction implicite { os << num << "/" << den; } Fraction Fraction :: operator +(const Fraction &a) const /*surcharge d'oprateur additionne la fraction passee en reference implicite*/ { return Fraction(num * a.den + den * a.num, den * a.den).Simplifie(); } a la fraction

Fraction Fraction :: operator -() const /*surcharge d'oprateur renvoie la fraction opposee de la fraction implicite*/ { return Fraction(-num, den); } Fraction Fraction :: operator *(const Fraction &a) const /*surcharge d'oprateur fait le produit de la fraction passee en reference a la fraction implicite*/ { return Fraction(num * a.num, den * a.den).Simplifie(); } bool Fraction :: operator ==(const Fraction &a) const /*surcharge d'oprateur teste l'egalite de la fraction passee en reference avec la fraction implicite*/ { return (num * a.den == den * a.num); } bool Fraction :: operator <(const Fraction &a) const /*surcharge d'oprateur teste l'inferiorite de la fraction passee en reference a la fraction implicite*/ { return num * a.den < den * a.num; } const Fraction &Fraction :: operator ++() /*surcharge d'operateur incrmentation la fonction est const pour empecher par exemple ++x1 = x2*/ { num += den;

Conception et programmation oriente objet avec C++

54

PROGRAMMES

return *this; /*il faut renvoyer l'argument implicite sinon impossible de faire par exemple x2 = ++x1; car ++x1 ne renverrait rien */ } Fraction Fraction :: operator +=(const Fraction &a) /*surcharge d'operateur effectue a=a+b*/ { num = num * a.den + den * a.num; den *= a.den; (*this) = (*this).Simplifie(); return *this; // sinon x3 = x2 += x1; impossible } //---------------------------Implementation des fonctions ordinaires----------------Fraction Difference(const Fraction &a, const Fraction &b) /*fait la difference de deux fractions passees en parametre*/ { return a.Somme(b.Oppose()); } Fraction Quotient(const Fraction &a, const Fraction &b) /*fait la division de deux fractions passees en parametre*/ { return a.Produit(b.Inverse()); } Fraction Lire(istream &is) /*saisie d'une fraction depuis l'entre standard*/ { int a,b; is >> a >> b ; return Fraction(a,b) ; } ostream &operator <<(ostream &os, const Fraction &a) /*surcharge d'oprateur crit sur le flux de sortie la fraction*/ { a.Ecrire(os); return os; } istream &operator >>(istream &is, Fraction &a) /*surcharge d'oprateur saisie sur le flux d'entre la fraction*/ { a = Lire(is); return is; } Fraction operator -(const Fraction &a, const Fraction &b) /*surcharge d'oprateur fait la difference de deux fractions passees en parametre*/ { return a + (-b); } Fraction operator /(const Fraction &a, const Fraction &b) /*surcharge d'oprateur fait la division de deux fractions passees en parametre*/ { return a * (b.Inverse()); } bool operator !=(const Fraction &a, const Fraction &b) /*surcharge d'oprateur teste la non egalite de deux fractions passees en parametre*/ { return !(a == b); } bool operator >(const Fraction &a, const Fraction &b) /*surcharge d'oprateur teste la superiorite de deux fractions passees en parametre*/ {

Conception et programmation oriente objet avec C++

55
return b < a; }

PROGRAMMES

bool operator <=(const Fraction &a, const Fraction &b) /*teste l'inferiorite ou egalite de deux fractions passees en parametre*/ { return !(a > b); } bool operator >=(const Fraction &a, const Fraction &b) /*teste la superiorite ou egalite de deux fractions passees en parametre*/ { return b <= a; }

7.

SYSTEMES.H

#ifndef SYSTEMESH #define SYSTEMESH Fraction Det(const Fraction Fraction &a22); /*calcule le dterminant |a11 a12| |a21 a22|*/ &a11, const Fraction &a12, const Fraction &a21, const

bool ResoutSystem2x2(const Fraction &a1, const Fraction &b1, const Fraction &a2, const Fraction &b2, const Fraction &c1, const Fraction &c2, Fraction &x, Fraction &y); /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ #endif

8.

SYSTEMES.CPP
<iostream> "entiers.h" "fractions.h" "systemes.h"

#include #include #include #include

Fraction Det(const Fraction &a11, const Fraction &a12,const Fraction &a21, const Fraction &a22) /*calcule le dterminant |a11 a12| |a21 a22|*/ { return Difference(a11.Produit(a22), a21.Produit(a12)); } bool ResoutSystem2x2(const Fraction &a1, const Fraction &b1, const Fraction &a2, const Fraction &b2, const Fraction &c1, const Fraction &c2, Fraction &x, Fraction &y) /* donnes : a1, a2, b1, b2, c1, c2 Rsultat : x, y et un boolen Taches : rsout a1x + b1y = c1, a2x + b2y = c2 Convention : si renvoie vrai x et y ont t calcul Si renvoie faux x et y sont indtermin*/ { Fraction d = Det(a1,b1,a2,b2), zero; if (d.Est_egal(zero)) return false; // pas d'arrondi car ce sont des entiers else { x = Quotient(Det(c1,b1,c2,b2),d); y = Quotient(Det(a1,c1,a2,c2),d); return true;

Conception et programmation oriente objet avec C++

56
} }

PROGRAMMES

9.

CHAINES.H

#ifndef CHAINESH #define CHAINESH #define DEBUG using namespace std; //------------------------- classe Chaine -------------------------------------class Chaine { char *t ; // pour l'instant il n'y a pas de tableau (pas de caractres), le tableau sera allou en cours d'excution void Alloue(const Naturel &n) ; // alloue n caractres public : Chaine () ; /* constructeur sans parametres cree un pointeur sur chaines de caracteres vide */ Chaine (const char *s) ; /* constructeur avec un pointeur sur chaine de caractere */ Chaine (const char &c) ; /*constructeur avec une variable de type chaine de caractere*/ Chaine (const Chaine &ch) ; // constructeur de copie ~ Chaine() ; // ~ est le symbole du destructeur Chaine (const Naturel &n, const char &c); // cre une chane contenant n fois le caractre c Naturel Longueur() const ; Chaine operator +(const Chaine & ch) const ; /*surcharge d'oprateur concatne la chaine passe en rfrence la chaine implicite*/ const Chaine &operator =(const Chaine &ch) ; /*surcharge d'oprateur affecte la chaine implicite la chaine passe en rfrence le rsultat est pass par rfrence*/ char operator [](const Naturel &i) const ; /*renvoie une valeur, sert consulter, 0 <= i <= (*this).Longueur() -1 */ char &operator [](const Naturel &i); // renvoie un objet, sert modifier bool operator <=(const Chaine &ch) const ; void Ecrire(ostream &os) const; // affiche sur la sortie standard la chaine implicite } ; ostream &operator <<(ostream &os,const Chaine &ch); /*surcharge d'oprateur crit sur le flux de sortie la chaine*/ istream &operator >>(istream &is, Chaine &ch); /*surcharge d'oprateur saisie sur le flux d'entre la chaine*/ #endif

10. CHAINES.CPP
#include #include #include #include <iostream> "erreurs.h" "entiers.h" "chaines.h"

//--------------- implementation de la classe Fraction ------------------------/*referencement des fonctions membres a sa classe d'origine*/ /*corps des fonctions*/ void Chaine :: Alloue(const Naturel &n) { t = new char[n] ; if (t == NULL) Erreur("Chaine:: Alloue(n): mmoire sature") ;

Conception et programmation oriente objet avec C++

57
}

PROGRAMMES

Chaine :: Chaine () /*constructeur sans parametres cre un pointeur sur chaines de caracteres vide*/ { Alloue(1) ; t[0] = '\0' ; } Chaine :: Chaine(const char *s) /*constructeur avec un pointeur sur chaine de caractere*/ { Alloue(1 + strlen(s)); strcpy(t, s); } Chaine :: Chaine (const /*constructeur avec une { Alloue(2) ; *t = c ; // quivaut *(t + 1) = '\0' ; // } char &c) variable de type chaine de caractere*/ t[0] = c ; quivaut t[1] = '\0' ;

Chaine :: Chaine(const Chaine &ch) /* constructeur de copie */ { Alloue(1 + strlen(ch.t)); strcpy(t, ch.t); cout << "Appel au constructeur de copie" ; } Chaine :: ~ Chaine() // ~ est le symbole du destructeur { delete []t ; // cout <<''appel au destructeur'' ; } Chaine :: Chaine (const Naturel &n, const char &c) // cre une chane contenant n fois le caractre c { } Naturel Chaine :: Longueur() const { return (Naturel) strlen(t); } Chaine Chaine :: operator +(const Chaine & ch) const /*surcharge d'oprateur concatene la chaine passe en rfrence la chaine implicite*/ { Chaine r(strlen(t) + strlen(ch.t),' ') ; strcpy(r.t, t) ; strcat(r.t, ch.t) ; return r; } const Chaine &Chaine :: operator =(const Chaine &ch) /*surcharge d'oprateur affecte la chaine implicite la chaine passe en rfrence le rsultat est pass par rfrence*/ { if (this != &ch) // evite ch = ch { delete []t; Alloue(1 + strlen(ch.t)); // t = new char[1 + strlen(ch.t)]; strcpy(t, ch.t); } return *this; }

Conception et programmation oriente objet avec C++

58

PROGRAMMES

char Chaine :: operator [](const Naturel &i) const /*surcharge d'oprateur renvoie une valeur, sert consulter, 0 <= i (*this).Longueur() -1 */ { #ifdef DEBUG if (i >= strlen(t)) Erreur("Chaine :: operator[](i) : l'lment i n'est dfini"); #endif return t[i]; } char &Chaine :: operator [](const Naturel &i) /*surcharge d'oprateur renvoie un objet, sert modifier */ { #ifdef DEBUG if (i >= strlen(t)) Erreur("Chaine :: operator[](i) dfini"); #endif return t[i]; } bool Chaine :: operator <=(const Chaine &ch) const /*surcharge d'oprateur*/ { return strcmp(t, ch.t) <= 0; } void Chaine :: Ecrire(ostream &os) const // affiche sur la sortie standard la chaine implicite { os << t; } //---------------------------Implementation des fonctions ordinaires-----------ostream &operator <<(ostream &os,const Chaine &ch) /*surcharge d'oprateur crit sur le flux de sortie la chaine*/ { ch.Ecrire(os); return os; } istream &operator >>(istream &is, Chaine &ch) /*surcharge d'oprateur saisie sur le flux d'entre la chaine*/ { static char s[1024]; is.getline(s, 1023, ' '); ch = Chaine(s); return is; }

<=

pas

l'lment

n'est

pas

Conception et programmation oriente objet avec C++

59

LES LIBRAIRIES

LES LIBRAIRIES
Source : http://www.tcom.ch/Tcom/Cours/C++/C++.html . Voir galement : http://www.opengroup.org/onlinepubs/007908799/idx/index.html .

1.

LINTERET DES LIBRAIRIES

La librairie standard de UNIX est actuellement encore largement utilise. Mais il ne faut pas oublier qu'elle a t prvue pour une utilisation dans un cadre de programmation systme. Elle recle nombre de fonctions de trs bas niveau, ce qui, incidemment, en fait un outil trs performant dans le cadre de la programmation systme ou la programmation de microcontrleurs. Ainsi des routines couramment utilises sous UNIX, comme signal(), setjmp(), longjmp(), provoquent une rupture du droulement normal du programme qui peut poser de srieux problmes de rcupration de mmoire, en particulier pour des objets cres automatiquement, de manire pas toujours transparente par le compilateur. En principe, lorsqu'un groupe de travail se met dvelopper en C, il se met sur pied une librairie de procdures qui va crotre au cours du temps et au cours des projets. Cette dmarche ncessite une organisation, des rgles respecter absolument. Ces rgles sont fonction de la dimension du groupe de travail. Pour de petits groupes largement autonomes (10 personnes), on peut se contenter d'encourager les gens parler entre eux. Si cette communication ne va pas de soi, souvent en raison de problmes dincompatibilit entre les divers dveloppeurs, on peut "organiser" cet change de vues, sans que cela soit forcment une directive mise par un chef de groupe donn. En fait, une directive fonctionne gnralement mieux lorsqu'elle est spontanment applique. Une bonne mthode (et de surcrot facile rendre populaire dans nos contres) est l'organisation frquente de verres ou chacun parle de manire libre de ce qu'il fait. Pour des groupes de dveloppement plus importants, ou des projets regroupant plusieurs groupes (parfois distribus gographiquement), il n'est plus possible de se contenter d'une communication orale, et il faut recourir des documents pour changer les informations concernant les classes produites. La production de documents tant une entreprise longue et fastidieuse, on peut raisonnablement craindre que l'change d'informations ne se fasse pas aussi bien que l'on pourrait le souhaiter. C'est pourquoi l aussi, il est important de trouver des moyens permettant de favoriser des communications informelles entre les groupes de dveloppement. Ces communications ont de tous temps t prcieuses, elles le sont d'autant plus lorsque l'on dispose d'un outil potentiellement efficace pour changer du code. La cration de modules de librairies, dans ce contexte, doit faire l'objet de soins particuliers par les auteurs de code. Exporter des classes bogues n'apporte que des ennuis, tant l'auteur qu'aux utilisateurs. Dans le meilleur des cas, on n'utilisera plus les classes dveloppes par un auteur particulier, parce que trop souvent bogues. Dans le pire des cas, l'exportation d'une erreur dans plusieurs projets n'ayant en commun que la rutilisation d'un module particulier peut causer de graves problmes financiers une socit. Lors du dveloppement d'une classe, il est prudent de partir du principe que l'utilisateur est un ennemi potentiel, contre lequel il convient de se protger. Si il existe une condition qui peut entraner une erreur dans le code d'une classe, il est plus que vraisemblable qu'un utilisateur de cette classe dclenchera un jour ou l'autre cette condition. Une classe que l'on dsire exporter doit donc imprativement tre l'preuve de toute manipulation dont on sait qu'elle est dangereuse. Il vaut mieux avorter brutalement l'excution d'un programme avec un message d'erreur sur la console que de laisser se poursuivre une excution dans une situation d'erreur.

2.

LIBRAIRIE C STANDARD

La librairie C standard est certainement la plus utilise des librairies C++, bien quelle ne soit pas oriente objets. Le principal avantage de cette librairie est quelle est en partie normalise par lANSI, et de ce fait se retrouve sur toutes les implmentations ANSI du langage. La liste prsente dans le cadre de ce chapitre ne prtend pas tre exhaustive, mais prsente les principales fonctions de la librairie C telle quon la retrouve sur quasiment toutes les implmentations de C et de C++ ( lexception de certains compilateurs C de bas niveau, utiliss pour la programmation de chips spcialiss, comme des microcontrleurs et des processeurs de signaux, ou DSP). Il est important de se souvenir que cette librairie a t conue indpendamment de C++. Elle peut donc prsenter de srieuses incompatibilits avec certaines constructions plus modernes de C++. En pratique, ces incompatibilits ne sont pas gnantes, dans la mesure o lon ne mlange pas les fonctions de la librairie C avec les fonctions correspondantes dune libraire C++, ou pire, avec des instructions rserves de C++. Ainsi, le code suivant produira coup sr de srieuses difficults lutilisation :
const int nbPoint = 200; struct Point { int x, y; }; Point *pptr; pptr = calloc(nbPoint, sizeof(Point)); ...

Conception et programmation oriente objet avec C++

60
delete pptr; // suicidaire !

LES LIBRAIRIES

2.1.

GENERALITES (#INCLUDE <STDARG.H>)

void va_start(va_list varList, parameter); type va_arg(va_list varList, type); void va_end(va_list varList);

Ces macros permettent de dfinir des fonctions avec des listes darguments de longueur variable. Elles sont spcialement utilises pour des fonctions telles que printf() et scanf() entre autres, mais il est galement possible de dfinir des fonctions utilisant un nombre variable darguments des fins personnelles. La fonction suivante effectue la moyenne dun nombre arbitraire de valeurs relles positives:
#include <stdarg.h> double mean(float firstArg, ...) { va_list argList; double nextArg; double mean; int count; // Indiquer quel est le premier paramtre de la liste, // et initialiser les macros : va_start(argList, firstArg); mean = firstArg; next = 0; // Une valeur ngative sert de terminateur de la liste while ((next = va_arg(argList, double)) >= 0) { mean += next; count++; } // Ne pas oublier va_end !!! va_end(argList); return (mean / count); } void main() { printf(Resultat = %f\n, mean(1.5, 2.3, 4.2, 5, 6, 2.1)); }

Ces macros sont implmentes dans pratiquement toutes les implmentations de C ( en tout cas, toutes les implmentations compatibles avec le standard ANSI). Par lutilisation de classes en C++, il existe toutefois des mthodes autrement puissantes - et autrement plus lgantes- de rsoudre ce genre de problmes, si bien que nous ninsisterons pas plus longtemps sur cette possibilit.

2.2.

STDIO (#INCLUDE <STDIO.H>)

On connat dj stdio par le biais de printf() et scanf(). En principe, on conseille plutt lutilisation de iostream pour laccs des fichiers en C++. En pratique, stdio reste largement utilis, souvent pour les entres-sorties sur terminal. De plus, lutilisation de stdio par diverses librairies existantes est intensive, si bien quil vaut la peine de sintresser quand mme cette librairie. Dans le cadre de stdio, les conventions suivantes sont utilises pour dfinir le modes daccs aux fichiers : r : (Read) Le fichier est utilisable en lecture seulement. Pour louvrir, le fichier doit exister au pralable. w : (Write) Fichier utilisable en criture seulement. Ouvrir un fichier existant en mode. w surcrit le contenu prcdent de ce fichier. Si le fichier nexistait pas lors de louverture, il sera cre. a : (Append) Ouverture du fichier en mode ajout. Les donnes sont appondues la fin du fichier, mais ce dernier doit exister au moment de louverture. r+ : (Read and Update) Ouverture dun fichier existant en mode lecture / criture. w+, rw : (Read / write) Ouverture dun fichier en mode lecture / criture. Si ce fichier nexiste pas, alors il est cre. a+ : (Append / Create) Comme a, mais si le fichier nexiste pas, alors il est cre. La lettre b, ajoute une autre indication (comme par exemple wb+) indique quil sagit dun fichier binaire. Utilise dans le cadre de systmes comme MVS, VMS, etc.., cette indication est rarement utilise dans le cadre des systmes de gestion de fichiers modernes. Toutes les routines retournent un entier indiquant le rsultat -couronn de succs ou non- de lappel la fonction concerne. On peut choisir de ngliger ce rsultat ou non. En rgle gnrale, on testera le rsultat de louverture de fichier, et le programmeur choisira frquemment de ngliger les rsultats livrs par les autres oprations. Cette manire de faire est courante dans tous les langages, et dangereuse dans tous les langages. Dans le

Conception et programmation oriente objet avec C++

61

LES LIBRAIRIES

cadre des petits exemples donns avec les procdures, nous ngligerons frquemment de tester le rsultat de lopration, ceci afin de ne pas surcharger lexemple. En cas derreur, la cause de lerreur peut tre dduite de la variable errno. Les valeurs possibles de errno sont explicites dans le fichier errno.h.
FILE *fopen(const char* fileName,const char* mode);

Ouverture dun fichier du nom de fileName en mode mode. Le rsultat de lappel est un pointeur sur une variable dun type en principe opaque, qui sera pass ultrieurement aux autres fonctions de manipulation de fichiers. Si louverture choue, cest une valeur de pointeur NULL qui sera retourne.
FILE* fichier; fichier = fopen(porno.gif, r); if (fichier != NULL) { ... // Considrations anatomiques ? ... } FILE *freopen(const char* fileName, const char* mode, FILE* stream);

Ferme le fichier stream et ouvre en lieu et place le fichier nomm par fileName dans le mode mode. En cas dchec de louverture, un pointeur NULL est retourn, mais ltat du fichier ouvert prcedemment est indetermin (gnralement, il a t ferm). La valeur de la variable errno peut donner une indication quant ce quil sest effectivement pass.
FILE* fichier; fichier = freopen(anOtherStdout, w, stdout); // redirection de stdout sur un fichier... if (fichier == NULL) { printf(Redirection de stdout manque pour cause de %d\n, strerror(errno)); exit(1); } // else continuer allgrement le travail... int fclose(FILE* stream);

Fermeture du fichier associ au pointeur stream. Rappelons quen C, un fichier nest pas ferm implicitement lors de la destruction du pointeur fichier associ. Retourne 0 si succs, EOF dans le cas contraire. fclose() provoque un appel implicite fflush() pour vider le tampon associ stream.
FILE* f = fopen(tmp.tmp, w); fprintf(f, Contenu de fichier bidon\n); fclose(f); int fflush(FILE *stream)

Provoque lcriture force du tampon associ au fichier stream. En cas de succs, retourne 0, EOF en cas dchec. Si stream vaut NULL, tous les fichiers ouverts en criture seront vids.
printf(Ecriture dans le tampon...); if ((err = fflush(stdout))) { printf(fflush na pas fonctionn pour cause %d\n, errno); exit(0); } // Provoque lcriture force, malgr labsence de \n int remove(const char* name);

Destruction du fichier portant le nom name. Retourne 0 en cas de succs. Si le fichier portant le nom name tait ouvert au moment de lappel de remove(), le rsultat dpend de limplmentation (en particulier du systme dexploitation), mais gnralement, cette situation est signale comme une erreur.
int rename(const char* oldName,const char* newName);

Permet de renommer le fichier appel oldName en newName.Cette opration choue si le fichier dsign par newName existe dj (pas vrai pour toutes les implmentations). On trouve parfois galement rename(const char* oldName,

Conception et programmation oriente objet avec C++

62

LES LIBRAIRIES

int ref, const char* newName) comme dfinition. ref indique alors le volume sur lequel doit tre effectue cette opration. FILE* f = fopen(tmp.tmp, w); fprintf(f, Contenu de fichier bidon\n); fclose(f); rename(tmp.tmp, bidon.txt); f = fopen(bidon.txt, r); char buffer[200]; fscanf(f, %s, buffer); printf(%s, buffer); fclose(f); remove(bidon.txt); int setvbuf(FILE* stream, char *buf, int mode, size_t size); setvbuf() permet de dfinir comment les entres-sorties seront mises en tampon, et quelle sera la taille du tampon. Cet appel doit faire suite immdiatement lappel de fopen(), donc avant toute autre utilisation du fichier, sans quoi les rsultats peuvent devenir imprvisibles. stream pointe sur le descripteur de fichier pour lequel on dfinit le tampon, buf, pointe sur un tampon mmoire de taille size, et mode peut prendre lune des trois valeurs suivantes : _IOFBF (Full BuFfering) _IOLBF (Line BuFfering) _IONBF (No BuFfering)

A noter que beaucoup dimplmentations de librairies offrent la possibilit deffectuer cet appel implicitement, de manire combine lappel fopen(), si bien que lappel explicite nest plus ncessaire. Cette fonction tend de ce fait ne plus tre utilise, sauf dans des cas particuliers o lon dsire forcer une dimension de tampon trs grande pour des fichiers de trs grande taille. Cette fonction retourne 0 en cas de succs. Un appel cette fonction aprs une opration sur le fichier (lecture ou criture) a un rsultat indfini.
void setbuf(FILE* stream, char *buf);

Lappel de cette fonction correspond appeler setvbuf en mode _IONBF, avec size 0 si buf est NULL. Si buf nest pas NULL, il doit avoir au pralable t dfini la librairie par un appel dpendant de limplmentation. La longueur du buffer, en particulier correspondra la longueur par dfaut du tampon fichier (souvent un multiple dun bloc disque).
FILE* tmpfile(void);

Cre un fichier temporaire qui sera automatiquement dtruit lors de la fermeture de ce fichier, ou la fin du programme (dans la mesure o le programme peut se terminer normalement, bien sr). Le fichier sera ouvert en mode wb+.
char* tmpnam(char* name);

Gnre un nom de fichier correct par rapport au systme dexploitation, et unique dans lenvironnement dexcution. Si name est diffrent de NULL, le nom gnr sera crit dans la chane fournie en paramtre. La longueur minimale de cette chane dpend de limplmentation (en particulier du systme dexploitation considr). Le nombre maximum de noms diffrents que peut gnrer tmpnam() dpend de limplmentation, mais devrait dans tous les cas tre suprieur 9999. Si name est NULL, il faut se rfrer limplmentation pour savoir comment grer le pointeur retourn par tmpnam(). Certaines implmentations (la plupart, en fait) utilisent une chane de caractres statique qui sera rutilise chaque appel de tmpnam(), lancien contenu se trouvant ds lors surcrit. Plus rarement, une nouvelle chane sera gnre en mmoire, par un appel malloc(); dans ce cas, il faudra que le programme appelant prenne en charge la destruction de cette chane par un appel free().
int printf(const char* controlString, ...); printf crit une chane de caractres formatte sur la sortie standard (stdout). La formattage est dfini par la chane de caractres controlString, alors que les arguments sont contenus dans une liste de longueur indfinie. Un descripteur de format est indiqu par le caractre % suivi dun caractre indiquant la conversion effectuer. Ainsi, la squence %d indique quil faut interprter largument correspondant (dfini par sa position dans controlString et dans la liste darguments) comme un entier dcimal. En cas de succs, printf retourne le nombre de caractres imprims sur stdout, sinon, EOF. printf(La valeur de pi est %7.5f\n, 3.1415926);

imprime sur la sortie standard :


La valeur de pi est 3.14159

Conception et programmation oriente objet avec C++

63

LES LIBRAIRIES

Autres rfrences : Voir Descripteurs de formats de printf().


int scanf(const char* controlString, ...); scanf convertit des entres en provenance de lentre standard stdin en une srie de valeurs, en se servant de controlString comme modle de conversion. Les valeurs sont stockes dans les variables sur lesquelles pointe la liste darguments indique par ... dans le prototype. La chane controlString contient des descriptions de format qui indiquent scanf comment il convient de convertir les entres de lutilisateur. Un descripteur de format est indiqu par le caractre % suivi dun caractre indiquant la conversion effectuer. Ainsi, la squence %d indique quil faut interprter les entres sur stdion comme un entier dcimal. scanf retourne le nombre darguments auxquels il a t possible dassigner une valeur. Ce nombre peut tre diffrent du nombre darguments pass scanf ! Si il nest pas possible de lire sur stdin, EOF sera retourn. int x; printf(Entrer une valeur entire: ); scanf(%d, &x); printf(Vous avez entr %d\n, x);

Autres rfrences : Voir Descripteurs de formats de printf().


int fprintf(FILE* f, const char* controlString, ...);

Fonctionnalit quivalente printf(). De fait, printf() peut galement scrire fprintf(stdout, Valeur de pi = %f\n, 3.1415926);
int fscanf(FILE *f, const char* controlString, ...)

Fonctionnalit quivalente scanf(). De fait, scanf() peut galement scrire :


float unReel; print(Entrer un nombre reel ); fscanf(stdout, %f, unReel); int sprintf(char *buffer, const char* controlString, ...);

Fonctionnalit quivalente fprintf(), mais la sortie se fait dans une chane de caractres en lieu et place dun fichier. Lutilisateur devra veiller lui-mme rserver une place suffisante dans la chane rfrence par *buffer.
int fgetc(FILE *stream);

Lecture du prochain caractre dans le fichier associ au pointeur stream. Le fait que le rsultat soit entier (au lieu de char) est d la possibilit de livrer EOF (de type int) en cas derreur. Pratiquement, du fait de la conversion implicite int <-> char, ceci na pas vraiment dimportance. Valeurs de retour : le prochain caractre si lopration est couronne de succs. EOF (ngatif, en gnral) si il y a une erreur.
char* fgets(char* str, int nbChars, FILE *stream);

Lecture dune chane de caractres du fichier associ au pointeur stream dans la zone mmoire pointe par str. str doit pointer sur une zone mmoire de dimension au moins gale nbChars + 1 (+ 1 en raison du caractre \0 qui termine une chane de caractres en C). Cest au programmeur de sassurer que la place quil a reserve est suffisante. La fonction fgets() lit des caractres jusqu un caractre de fin de ligne, ou jusqu la lecture de nbChars caractres. Valeurs de retour : str si lopration est couronne de succs. NULL si il y a une erreur.
int fputc(int c, FILE* stream);

Ecriture du caractre c (donn sous forme dentier) dans le fichier associ au pointeur stream. Retourne la valeur entire de c en cas de succs, EOF autrement. On ne peut donc pas sans autre crire EOF au moyen de fputc().
// Copie dun fichier dans un autre : FILE* source; FILE* copy; int x;

Conception et programmation oriente objet avec C++

64

LES LIBRAIRIES

if ((source = fopen(source.dat, r)) == NULL) { printf(Erreur louverture de source.dat, %s\n, strerror(errno)); exit(1); } if ((source = fopen(copy.dat, w)) == NULL) { printf(Erreur louverture de copy.dat, %s\n, strerror(errno)); exit(1); } while ((x = fgetc(source)) != EOF) fputc(x); fclose(source); fclose(copy); int fputs(const char* str, FILE* stream);

Ecrit la chane de caractres pointe par str dans le fichier point par stream. Retourne 0 en cas de succs, EOF en cas dchec.
int getc(FILE* stream); int putc(int c, FILE* stream);

Implmentations sous forme de macros de fgetc() et fputc(). Comportement en principe similaire.


int puts(const char* str);

Identique fputs(), mais criture sur stdout.


char* gets(char* str);

Identique fgets(), mais lecture partir de stdin.


int getchar(void)

Retourne la valeur du prochain caractre, sous forme dun entier, lu sur stdin. Retourne EOF en cas derreur.
int putchar(int car);

Ecrit le caractre car (donn sous forme dentier) sur stdout. Retourne car en cas de succs, EOF en cas derreur.
int ungetc(int c, FILE* stream);

Rinsre le caractre c dans le fichier associ au pointeur stream. Retourne c en cas de succs, EOF en cas dchec.
size_t fread(void* buffer, size_t sizeOfItem, size_t count, FILE* stream);

Lecture de count lments de taille sizeOfItem du fichier associ au pointeur stream dans le tampon buffer. La fonction retourne le nombre dlments lus en cas de succs, ou EOF en cas derreur.
size_t fwrite(const void *buffer, size_t sizeOfItem, size_t count, FILE* stream);

Ecriture de count lments de taille sizeOfItem du tampon buffer dans le fichier associ au pointeur stream. La fonction retourne le nombre dlments crits en cas de succs, ou EOF en cas derreur.
#include <stdio.h> typedef struct { int a; char b; } Foo; void main () { FILE *fp; int i; Foo inbuf[3]; Foo outbuf[3] = { { 1, 'a' }, { 2, 'b' }, { 3, 'c' } };

Conception et programmation oriente objet avec C++

65

LES LIBRAIRIES

fp = fopen( "MyFooFile", "wb+"); fwrite( outbuf, sizeof(Foo), 3, fp ); rewind( fp ); fread( inbuf, sizeof(Foo), 3, fp ); for ( i=0; i<3; i++ ) printf( "foo[%d] = { %d %c }\n", i, inbuf[i].a, inbuf[i].b ); fclose( fp ); } int fgetpos(FILE* stream, fpos_t* position);

Cette fonction livre dans la variable pointe par position la position dans le fichier associ au pointeur stream. Le type fpos_t est un type opaque, qui ne devrait tre utilis quen conjonction avec fsetpos(). Cette fonction retourne 0 en cas dexcution correcte.
int fsetpos(FILE* stream, fpos_t* position);

Permet de se repositionner dans le fichier associ au pointeur stream la position position. position doit imprativement avoir t livr par fgetpos(), sinon le programme peut ne plus tre portable. Retourne 0 en cas de succs.
#include <stdio.h> void main() { FILE *fp; fpos_t pos; char s[80]; fp = fopen( "MyFile", "w+" ); fgetpos( fp, &pos ); fputs( "Hello world.", fp ); fsetpos( fp, &pos ); fgets( s, 80, fp ); printf( "You read: %s\n", s ); fclose( fp ); } long ftell(FILE* stream);

Retourne la position courante dans le fichier associ au pointeur stream. Contrairement fgetpos, ftell est limit la taille dun long pour exprimer la position courante du fichier, et ne convient de ce fait pas aux trs grands fichiers. ftell retourne -1L en cas dchec, et ajuste errno la valeur reprsentant la cause de lerreur.
int fseek(FILE* stream, long offset, int how);

Permet de se positionner dans le fichier associ au pointeur stream. La position est exprime par la valeur offset, qui sera interprte en fonction du paramtre how. how peut prendre les trois valeurs suivantes : SEEK_SET : position doit tre interprt par rapport au dbut du fichier. SEEK_CUR : position doit tre interprt comme un dplacement relatif la position courante dans le fichier. SEEK_END : position doit tre interprt comme un dplacement relatif la fin du fichier. Le systme dexploitation sous-jacent peut imposer des restrictions fseek, en particulier lorsquon lapplique des fichiers texte. Il est recommand de jeter un coup doeil la documentation livre avec lenvironnement de dveloppement en cas de doute.
#include <stdio.h> void main() { FILE *fp; long int pos; char s[80]; fp = fopen( "MyFile", "w+" ); pos = ftell( fp ); fputs( "Hello world.", fp ); fseek( fp, pos, SEEK_SET ); fgets( s, 80, fp );

Conception et programmation oriente objet avec C++

66
printf( "You read: %s\n", s ); fclose( fp ); } void rewind(FILE* fstream);

LES LIBRAIRIES

Equivalent fseek(stream, 0L, SEEK_SET);


void clearerr(FILE* stream);

Efface une condition derreur pralablement mise sur le fichier associ au pointeur stream.
int feof(FILE *stream);

Teste si le fichier associ au pointeur stream est positionn en fin de fichier, cest--dire si une opration dentre-sortie prcdente a caus une erreur. feof() retourne 0 si la position actuelle dans le fichier nest pas la fin du fichier.
#include <stdio.h> void main() { FILE *fp; char c; fp = fopen( "MyFile", "w+" ); c = fgetc( fp ); if ( feof(fp) ) printf( "At the end of the file.\n" ); else printf( "You read %c.\n", c ); fclose( fp ); } int ferror(FILE* stream);

Retourne le code derreur pour le fichier associ au pointeur stream, si une erreur a eu lieu. Le code derreur vaut 0 si aucune erreur na eu lieu. Le code derreur est remis automatiquement zro par un appel rewind(), ou explicitement par un appel clearerr().
void perror(const char* str);

Permet dafficher sur stderr le message derreur en clair associ la valeur actuelle de errno. On peut ajouter la chane de caractres pointe par str ce message. errno nest pas utilis que pour les erreurs dentre-sorties, comme le montre lexemple suivant :
#include <stdio.h> #include <math.h> #include <errno.h> void main() { double i, result; i = -4.0; result = sqrt(i); if ( (result==0) & (errno!=0) ) perror( "Invalid argument for sqrt()" ); else printf( "The square root of %f is %f\n", i, result ); }

2.3.

STDLIB (#INCLUDE <STDLIB.H>)

La plus utilise (implicitement ou explicitement) des librairies C. Attention! Certaines des entres de cette librairie peuvent entrer en conflit avec des instructions spcifiques C++. Il sagit en particulier des instructions permettant de rserver de la mmoire, comme malloc(), calloc(), realloc(), free().

Conception et programmation oriente objet avec C++

67
void* malloc(size_t size);

LES LIBRAIRIES

malloc() permet lallocation dynamique de mmoire en cours dexcution du programme. En cas de succs de lallocation, il retourne un pointeur sur le bloc mmoire reserv, et en cas dchec, il retourne la valeur NULL. La dimension du bloc rserver est donne en paramtre. Le type size_t dpend de limplmentation: le plus souvent, size_t correspond long. struct Complex { double real, imag; }; Complex* cptr; // Rserver de la place pour un tableau de complexes int size; printf(Dimension du tableau ? ); scanf(%d, &size); cptr = malloc(size*sizeof(Complex)); if (cptr == NULL) { perror(Allocation mmoire refuse); exit(1); } malloc() neffectue aucune initialisation de la zone mmoire reserve. En C++, il faut absolument prfrer le mot rserv new. malloc() nutilise pas les constructeurs de classes. void* calloc(size_t num, size_t size); calloc() permet de rserver de la place mmoire pour un tableau de num lments ayant chacun une taille size. En cas de succs de lallocation, il retourne un pointeur sur le bloc mmoire reserv, et en cas dchec, il retourne la valeur NULL. Lexemple prcdent peut se rcrire, avec calloc(), de la manire suivante : struct Complex { double real, imag; }; Complex* cptr; // Rserver de la place pour un tableau de complexes int size; printf(Dimension du tableau ? ); scanf(%d, &size); cptr = calloc(size, sizeof(Complex)); if (cptr == NULL) { perror(Allocation mmoire refuse); exit(1); }

Contrairement malloc(), calloc() effectue une initialisation de la zone mmoire reserve. Cette initialisation consiste mettre tous les bits de la zone mmoire considre zro. En C++, il faut absolument prfrer le mot rserv new. malloc() nutilise pas les constructeurs de classes.
void* realloc(void *ptr, size_t size); realloc() permet de modifier la taille dun bloc mmoire rserv pralablement au moyen de calloc() ou malloc(). Pour ce faire, le bloc considr, point par ptr, est recopi en un autre endroit de la mmoire, dont la taille correspond size. En cas de succs de lallocation, il retourne un pointeur sur le bloc mmoire reserv, et en cas dchec, il retourne la valeur NULL. Si ptr vaut NULL lors de lappel de realloc(), cet appel a le mme effet que malloc(). Si ptr nest pas NULL, et que size vaut 0, alors cet appel est quivalent free(). Lors de laugmentation de la taille dune zone mmoire, les bits nouvellement allous ne sont pas initialiss. Lors de la diminution de taille mmoire, les bits excdentaires sont perdus. Le changement de taille du tableau reserv dans lexemple prcdent pourrait scrire: int newSize; printf(Nouvelle dimension du tableau ? ); scanf(%d, &newSize); cptr = realloc(cptr, sizeof(Complex) * newSize); if (cptr == NULL)

Conception et programmation oriente objet avec C++

68
{

LES LIBRAIRIES

perror(Allocation mmoire refuse); exit(1); }

Attention ! il faut se souvenir que, contrairement calloc(), realloc() neffectue aucune initialisation ! En C++, il faut absolument prfrer le mot rserv new. realloc() nutilise pas les constructeurs de classes, ni les oprateurs de copie.
void free(void* ptr); free() permet de librer la place mmoire rserve par malloc(), calloc() ou realloc(). Le pointeur pass free() comme argument doit imprativement avoir t rserv par lune de ces instructions, sans quoi les rsultats de lappel sont imprvisibles (le plus probablement, un crash du programme). Passer un pointeur NULL free() na pas deffet. char* str = malloc(200 * sizeof(char)); ... free(str); int abs(int i);

Valeur absolue de i.
div_t div(int numerateur, int denominateur);

Livre la partie entire et le reste de la division de numerateur/denominateur.


#include <stdio.h> #include <stdlib.h> void main () { int n = 32452, d = 787; div_t r; r = div(n,d); printf( "%d / %d vaut %d\n", n, d, r.quot ); printf( "et le reste vaut %d.\n", r.rem); } long labs(long j);

Valeur absolue pour des long.


int rand(void);

Retourne une valeur alatoire uniformment distribue entre 0 et RAND_MAX. Ne convient pas pour des applications ncessitant des nombres caractristiques statistiques de bonne qualit.
void srand(unsigned int seed);

Permet dinitialiser le gnrateur de rand une valeur prdetermine.


void* bsearch(const void *key, const void* array, (*comparison)(const void *key, const void *data)); size_t count, size_t size, int

Recherche dichotomique ( binary search) de llment key dans le tableau array. Le tableau comporte count lments, chacun de taille size. Lutilisateur fournit la fonction permettant de comparer deux lments; cette fonction doit retourner un rsultat < 0 si key est plus petit que llment considr, 0 si key est gal llment, et > 0 si key est plus grand que llment compar. Le tableau array doit avoir pralablement t tri par ordre ascendant, de manire permettre la recherche dichotomique. On pourra utiliser qsort() pour ce faire.
#include <stdio.h> #include <string.h> #include <stdlib.h>

Conception et programmation oriente objet avec C++

69

LES LIBRAIRIES

int compare( const void *s1, const void *s2 ) { return strcmp( s1, s2 ); } int Findname( char *name ) { char *result; static char infoProfs[][15] = { "Breguet", "Evequoz", "Guerid", "Molliet", "Pesenti", "Roethlisberger" }; result = bsearch( name, infoProfs, 6, sizeof(char[15]), compare ); return ( result != NULL ); } void main() { char name[80]; printf( "Votre nom SVP ? " ); scanf( "%s", name ); printf(%s , name); if ( Findname(name) ) printf( "est"); else printf( "nest pas"); printf( un prof dinformatique lEINEV\n); } void qsort(void* array, size_t count, size_t size, int (*comparison)(const void *key, const void *data));

Ralise le tri en place dun tableau array comportant count lments de taille size. Lutilisateur fournit lui-mme la fonction de comparaison; cette fonction doit retourner un rsultat < 0 si key est plus petit que llment considr, 0 si key est gal llment, et > 0 si key est plus grand que llment compar. Lalgorithme de tri utilis est celui d R. Sedgewick, appel quicksort. Il consiste partitionner le tableau trier en tableaux partiels que lon triera individuellement.
#include <stdlib.h> #include <stdio.h> const int ASIZE = 10; const int AMAX = 100; int compare( const void *n1, const void *n2 ) { return ( *((int *) n1) - *((int *) n2) ); } void main() { int a[ASIZE], i; srand( (unsigned int) clock() ); // Initialisation dun tableau dentiers // avec des nombres alatoires for ( i=0; i<ASIZE; i++ ) a[i] = rand() % AMAX; printf( "Avant tri par qsort():\n\t" ); for ( i=0; i<ASIZE; i++ ) printf( "%2d ", a[i] ); putchar('\n'); qsort( a, ASIZE, sizeof(int), compare ); printf( "Aprs tri par qsort():\n\t" ); for ( i=0; i<ASIZE; i++ ) printf( "%2d ", a[i] ); putchar('\n'); }

Conception et programmation oriente objet avec C++

70
double atof(void char* str);

LES LIBRAIRIES

Conversion dune chane de caractres en une valeur de type double.


#include <stdio.h> #include <stdlib.h> void main() { char *s1 = "3.141593"; char *s2 = "123.45E+676COUCOU!"; double result; result = atof( s1 ); printf( "s1 vaut %G.\n", result ); result = atof( s2 ); printf( "s2 vaut %G.\n", result ); }

Rsultat : s1 vaut 3.141593 s2 vaut 1.2345E+676


int atoi(const char* str); long int atol(const char* str);

Conversions de chanes de caractres en un entier ou en un long entier, respectivement.


double strtod(const char *str, char **end);

Convertit str en une valeur en double prcision. La conversion saute des blancs initiaux, dbute ds quun nombre est rencontr, et sarrte ds quun caractre non traduisible est trouv. Cest ladresse de ce caractre qui sera retourne dans end. end peut tre rutilis pour des appels successifs dans le cas de conversions en chane. atof(str) est quivalent strtod(str, NULL). Une conversion impossible livre 0 comme valeur de retour, et errno est mis E_RANGE. Si une conversion dpasse les limites de la machine, la valeur HUGE_VAL est retourne (voir <limits.h>).
long int strtol(const char* str, char** end, int base); unsigned long strtoul(const char* str, char** end, int base);

Conversion dune chane de caractres en une valeur entire longue, respectivement longue non signe. Obit au mmes principes que strtod. En plus, il est possible de spcifier une base de conversion comprise entre 2 et 36. Si la base vaut 0, la fonction va chercher dterminer la base du nombre au moyen du prfixe.
#include <stdio.h> #include <stdlib.h> main() { char *s1 = "3723682357boo!"; char *s2 = "0xFACES"; unsigned long int result; char *end; result = strtoul( s1, &end, 10 ); printf( "s1 vaut %lu, avec '%s' laiss non converti.\n", result, end ); result = strtoul( s2, &end, 0 ); printf( "s2 vaut %lu, avec '%s' laiss non converti.\n", result, end ); }

2.4.

MATH (#INCLUDE <MATH.H>)

Cette librairie ne pose pas de problmes particuliers lutilisation. Il faut toutefois se rappeler que la librairie math travaille en double prcision, et que lutilisation en conjonction avec des variables en virgule flottante peut amener certains compilateurs gnrer des avertissements, dans le cas o la conversion automatique nest pas sre.

Conception et programmation oriente objet avec C++

71
double sin(double x); double tan(double x); double cos(double x);

LES LIBRAIRIES

Fonctions trigonomtriques sinus, cosinus et tangente.


double acos(double x); double asin(double x); double atan(double x);

Arc cosinus, arc sinus et arc tangente.


double atan2(double x, double y);

Arc tangente de y/x.


#include <stdio.h> #include <math.h> void main() { double x, y, result; printf( "Enter x: " ); scanf( "%lf", &x ); printf( "Enter y: " ); scanf( "%lf", &y ); result = atan2(x,y); printf( "atan2( %G/%G ) = %G\n", x, y, result); } double sinh(double x); double cosh(double x); double tanh(double x);

Sinus hyperbolique, cosinus hyperbolique et tangente hyperbolique.


double double double double exp(double x); log(double x); log10(double x); sqrt(double x);

Exponentielle, logarithme naturel, logarithme en base 10, et racine carre. Des erreurs eventuelles (log(-4)) seront signales par le biais de errno.
double fabs(double x);

Valeur absolue.
double floor(double x); double ceil(double x);

Arrondi entier par troncature, arrondi entier par excs. Noter que lentier rsultant est retourn sous forme dun double.
double fmod(double x, double y);

Livre le reste de la division de x par y. errno est mis EDOM si y == 0.


#include <stdio.h> #include <math.h> void main() { double x, y, result; printf( "Enter x: " ); scanf( "%lf", &x ); printf( "Enter y: " ); scanf( "%lf", &y );

Conception et programmation oriente objet avec C++

72
} double ldexp(double x, int exposant); double frexp(double x, int *exposant);

LES LIBRAIRIES

result = fmod( x, y ); printf( "The remainder of %G/%G is %G.\n",x, y, result );

ldexp() retourne xexposant, alors que frexp() dcompose un nombre en ses deux parties x et exposant. Ces deux fonctions sont inverses lune de lautre. double modf(double x, double* intpart);

Retourne la partie dcimale de x, et dans la variable points par intpart, la partie entire.
double pow(double x, double y);

Retourne xy.

2.5.

CTYPE (#INCLUDE <CTYPE.H>)

Dans de nombreuses implmentations de librairies, les fonctions de ctype, permettant la manipulation de caractres, sont implmentes sous forme de macro. Il faut souligner que ces fonctions doivent tre prfres un test direct bas sur un code ASCII, qui pourrait ne pas tre utilis sur une machine utilisant un systme dexploitation diffrent. Les caractres sont gnralement traits comme des entiers par cette librairie.
int isalnum(int c);

Retourne TRUE (vrai) si c est un caractre alphanumrique (lettre ou chiffre).


int isalpha(int c);

Retourne TRUE (vrai) si c est un caractre alphabtique (lettre majuscule ou minuscule).


int iscntrl(int c);

Retourne TRUE (vrai) si c est un caractre de contrle (exemple, ESCAPE).


int isdigit(int c);

Retourne TRUE (vrai) si c est un chiffre.


int isgraph(int c);

Retourne TRUE (vrai) si c est affichable, et diffrent de SPACE.


int islower(int c);

Retourne TRUE (vrai) si c est une lettre minuscule.


int isprint(int c);

Retourne TRUE (vrai) si c est un caractre affichable ou un espace (SPACE).


int ispunct(int c);

Retourne TRUE (vrai) si c est un caractre diffrent dune lettre, dun chiffre, ou dun caractre de contrle.
int isspace(int c);

Retourne TRUE (vrai) si c est un espace (SPACE), un tabulateur, une fin de ligne, un tabulateur vertical (interligne), un saut de page.

Conception et programmation oriente objet avec C++

73
int isupper(int c);

LES LIBRAIRIES

Retourne TRUE (vrai) si c est une lettre majuscule.


int isxdigit(int c);

Retourne TRUE (vrai) si c est un chiffre hxadcimal.


int tolower(int c);

Retourne le rsultat de la conversion de c en minuscule. Si c nest pas une lettre majuscule, il sera retourn inchang.
#include <stdio.h> #include <ctype.h> void main() { char uc, lc; printf("Entrer une majuscule: "); uc = getchar(); lc = tolower( uc ); if ( uc != lc ) printf( "Minuscule de '%c' est '%c'.\n", uc, lc ); else printf("Pas de conversion en minuscule possible pour '%c'.\n",uc ); } int toupper(int c);

Retourne le rsultat de la conversion de c en majuscule. Si c nest pas une lettre minuscule, il sera retourn inchang.

2.6.

STRING (#INCLUDE <STRING.H>)

string est un module trs apprci des programmeurs en C et C++. Il faut toutefois se mfier de lutilisation incontrle de string en C++, puisque ce module fait usage, dans certains cas, de malloc() et free(). En pratique, tant que le programmeur nutilise que les primitives de string, et ne les mlange pas avec les instructions correspondantes de C++, il ny a pas de problmes particuliers utiliser string, sinon que certaines librairies C++ implmentent les mmes fonctionnalits de manire plus confortable. void *memcpy(void* dest, const void* source, size_t size);

Copie de size bytes de la zone pointe par source vers la zone pointe par dest. Attention, si les deux zones mmoires se chevauchent, il peut y avoir destruction de donnes.
#include <stdio.h> #include <string.h> typedef struct { int a; int b; } Foo; void main() { Foo foo1 = { 123, 456 }; Foo foo2 = { 987, 321 }; printf( "Before memcpy():\n" " foo1 = %d, %d foo2 = %d, %d\n", foo1.a, foo1.b, foo2.a, foo2.b ); memcpy( &foo1, &foo2, sizeof(Foo) ); printf( "After memcpy():\n" " foo1 = %d, %d foo2 = %d, %d\n", foo1.a, foo1.b, foo2.a, foo2.b ); } void* memmove(void* dest, const void* source, size_t size);

Conception et programmation oriente objet avec C++

Comme memcpy(), mais la fonction est execute correctement mme si les zones mmoirese chevauchent.

74

LES LIBRAIRIES

char* strcpy(char* dest, const char* source);

Comme memcpy(), mais pour le cas particulier o les zones mmoires sont occupes par des chanes de caractres. Attention sassurer que la place reserve dans dest est bien suffisante pour stocker la longueur de source!
#include <stdio.h> #include <string.h> void main() { char *source = "Au revoir"; char dest[25] = "Bonjour"; printf( "Avant strcpy(): dest = \"%s\"\n", dest ); strcpy( dest, source ); printf( "Apres strcpy(): dest = \"%s\"\n", dest ); } char* strncpy(char* dest, const char* source, size_t size);

Comme memcpy(), mais pour le cas particulier o les zones mmoires sont occupes par des chanes de caractres. La copie sarrte soit aprs copie du caractre de fin de chane (\0), soit aprs copie de size caractres.
char* strcat(char* dest, const char* source);

Concatnation de dest et de source, et dpose du rsultat dans dest. Attention sassurer que la place reserve dans dest est bien suffisante pour stocker la longueur de dest + source!
#include <stdio.h> #include <string.h> void main() { char s1[25] = "hello "; char *s2 = "world"; printf( "Avant strcat(): s1 = \"%s\"\n", s1 ); strcat( s1, s2 ); printf( "Apres strcat(): s1 = \"%s\"\n", s1 ); } char* strncat(char* dest, const char* source, size_t size);

Concatnation de dest et de source, et dpose du rsultat dans dest. La concatnation sarrte au plus tard aprs la dpose de size caractres dans dest.
int memcmp(const void* m1, const void* m2, size_t size);

Compare size lments entre les deux zones mmoire indiques. Retourne 0 si elles sont gales, > 0 si m1 est plus grand que m2, < 0 si m1 est infrieur m2. Lopration sarrte aussi tt que le rsultat est connu.
#include <stdio.h> #include <string.h> typedef struct { int a; int b; } Foo; void main() { Foo foo1, foo2; printf( "For each structure, enter two integers \n" "separated by a space, like: 123 987\n\n" ); printf( "Enter two numbers for foo1: "); scanf( "%d %d", &foo1.a, &foo1.b ); printf( "Enter two numbers for foo2: "); scanf( "%d %d", &foo2.a, &foo2.b ); if ( memcmp(&foo1, &foo2, sizeof(Foo)) == 0 )

Conception et programmation oriente objet avec C++

75

LES LIBRAIRIES

printf( "foo1 and foo2 are the same.\n" ); else printf( "foo1 and foo2 are different.\n" ); } int strcmp(const char* s1, const char* s2); int strcoll(const char* s1, const char* s2);

Comme memcmp(), mais pour des chanes de caractres. strcoll() respecte en plus les conditions locales dutilisation, qui peuvent inclure certaines rgles particulires un langage donn.
#include <stdio.h> #include <string.h> main() { char s1[80], s2[80]; int result; printf( "Premire chane (s1): "); scanf( "%s", s1 ); printf( "Seconde chane (s2): "); scanf( "%s", s2 ); result = strcmp( s1, s2 ); if ( result > 0 ) printf( "s1 est plus grand que s2.\n" ); else if ( result < 0 ) printf( "s1 est infrieur s2.\n" ); else printf( "s1 et s2 sont identiques.\n" ); } int strncmp(const char* s1, const char* s2, size_t size);

Comme memcmp(), mais pour des chanes de caractres. La comparaison sarrte aprs un maximum de size caractres, et au plus tt lorsque le rsultat est connu.
void* memchr(const void* str, int c, size_t size);

Retourne un pointeur sur le premier caractre identique c trouv dans les size premiers caractres de la chane str. Si c nst pas trouv, memchr() retourne NULL.
char* strchr(const char* str, int c);

Retourne un pointeur sur le premier caractre identique c trouv dans la chane str. Si c nst pas trouv, strchr() retourne NULL. Identique memchr() pour des chanes termines par \0.

2.7.

SIGNAL (#INCLUDE <SIGNAL.H>)

Ces groupes de fonctions permettent de grer des vnements asynchrones au programme. Il ne faut pas confondre ce mcanisme avec un traitement dexceptions tel quon le trouve en C++ ou en ADA : il sagit plutt de communications lmentaires entre processus asynchrones, voire de traitement dinterruptions ou derreurs de la librairie. Dans les implmentations minimales de C, les signaux disponibles refltent les limitations du systme dexploitation, et se limitent des vnements internes au programme (erreurs mathmatiques, time-outs, etc...). Dans le cadre dimplmentations UNIX, par contre, les signaux disponibles sont beaucoup plus riches; en revanche, lutilisation de cette richesse tend rendre les programmes difficiles porter.
void (*signal(int sig, void(*func)(int)))(int);

Dtermine la fonction appeler lorsque le signal sig sera mis.


int raise(int sig);

Provoque lmission du signal sig.

Conception et programmation oriente objet avec C++

76
3.

LES LIBRAIRIES

IOSTREAM (#INCLUDE <IOSTREAM.H>)

iostream est une librairie standard de C++. Cette librairie dfinit les flots dentresortie, et sert remplacer la librairie stdio de C. Un flot est un canal (recevant, dentre ou fournissant, de sortie) que lon peut associer un priphrique, un fichier, ou une zone mmoire. Un flot recevant ou dentre est un istream, (ifstream dans le cas dun fichier) alors quun flot de sortie est un ostream (ofstream dans le cas dun fichier). Logiquement, un flot dentre-sortie se dduit par hritage multiple dun istream et dun ostream pour former un iostream. Il existe des flots prdfinis : cout est le flot de sortie standard, connect la sortie standard stdout. cin est le flot dentre standard, qui est connect lentre standard stdin.

3.1.

OSTREAM

ostream redfinit loprateur << sous la forme dune fonction membre : ostream& operator << (expression) ; Lexpression correspondant au deuxime oprande peut tre dun type standard de base quelconque, y compris char ou char*. Si on veut utiliser cet oprateur pour des types dfinis par lutilisateur, il faudra le redfinir dans le cadre de la dclaration du type concern, gnralement sous forme dune fonction friend. Il nest pas possible de redfinir cet oprateur comme fonction membre, cause de lordre dinterprtation des oprandes. class X { friend ostream& operator << (ostream&, const X&); // oprandes dans lordre correct ... };

Lexemple i-dessous nest pas faux, mais est quasi inutilisable, car les oprandes vont se trouver inverss :
class X { public : ostream& operator << (ostream&); // les oprandes sont dans le mauvais ordre !!! };

Parmi les nombreuses fonctions membres, citons : ostream& put(char c); ostream& write(void* adressOfBuffer, long bufferSize);

3.2.

ISTREAM

istream redfinit loprateur >> de la manire suivante : istream& operator >> (& base_type); base_type peut tre un type de base quelconque, sauf un pointeur (char* est accept, nanmoins, pour la lecture de chanes de caractres). >> est compatible avec scanf, en ce sens que les espaces (espace, tabulateur, fin de ligne, saut de page, etc...) sont interprts comme des dlimiteurs. Pour redfinir loprateur dans le cas dun type utilisateur, utiliser la mme technique que pour ostream : class X { friend istream& operator >> (istream&, const X&); // oprandes dans lordre correct ... }; istream& get(char& c); int get(); // returns value of char at input, or EOF istream& read(void* bufferAdress, int bufferSize); // si moins de bufferSize caractres ont pu tre lus, la valeur // effectivement lue du nombre de caractres peut tre obtenue par : int gcount();

3.3.

IOSTREAM

Drive publiquement de istream et ostream, cette classe permet les entres-sorties conversationnelles, par exemple pour la lecture/criture sur un fichier.

Conception et programmation oriente objet avec C++

77
3.4. ETAT DUN FLOT

LES LIBRAIRIES

istream et ostream drivent de la classe ios, qui dfinit les constantes suivantes : eofbit : fin de fichier. failbit : la prochaine opration sur le flot ne pourra pas aboutir. badbit : le flot est dans un tat irrcuprable. goodbit : aucune des erreurs prcdentes.

Laccs aux nits derreur peut se faire par lune des fonctions membres suivantes : int eof() : valeur de eofbit. int bad() : valeur de badbit. int fail() : valeur de failbit. int good() : vrai (== 1) si aucun bit derreur nest activ. int rdstate() : valeur du mot dtat complet. Le mot dtat peut tre modifi par la mthode suivante : void clear(int newState = 0); Le mot dtat prend la valeur newState. Pour activer un bit (par exemple badbit sur le flot fl) on utilisera quelque chose comme : fl.clear(ios::badbit | fl.rdstate()); Lorsque lon lit un fichier, il arrive frquemment que lon crive une boucle du type : char buffer[1001]; int sze; while (!f.eof()) { // read the next chunk of data and process it f.read(buffer, 1000); for (int i = 0; i < f.gcount(); i++) { .... } } Il faut se souvenir qu la fin de cette boucle, fl.rdstate() est diffrent de zro. Aucune opration sur ce flot nest plus tolre. En particulier, si il sagit dun fichier accs alatoire, o lon peut librement positionner le pointeur de lecture dans le fichier, il ne sera plus possible de le positionner la sortie de la boucle, moins de remettre zro le mot dtat laide de : f.clear(); A chaque flot est associ un tat de formattage, constitu dun mot dtat et de 3 valeurs numriques associes, correspondant au gabarit, la prcision et au caractre de remplissage. Tableau 2 : signification du mot dtat de formatage Nom du champ Nom du bit Signification ios::dec conversion dcimale ios::oct conversion octale ios::basefield ios::hex conversion hexadcimale ios::showbase affichage de lindication de base ios::showpoint affichage du point dcimal ios::scientific notation dite scientifique ios::floatfield ios::fixed notation en virgule fixe Pour influencer le formatage, on peut utiliser soit des manipulateurs, soit des fonctions membres. Les manipulateurs peuvent tre paramtriques ou simples. Les manipulateurs simples sutilisent sous la forme : flot << manipulateur flot >> manipulateur Les principaux manipulateurs simples sont reprsents Tableau3. Tableau 3 : principaux manipulateurs simples Manipulateur Utilisation Action dec Entre/Sortie Active le bit de conversion dcimale hex Entre/Sortie Active le bit de conversion hexadcimale oct Entre/Sortie Active le bit de conversion octale endl Sortie Insre un saut de ligne et vide le tampon de sortie ends Sortie Insre un caractre de fin de chane (\0) Les manipulateurs paramtriques sutilisent sous la forme : istream& manipulateur(argument);

Conception et programmation oriente objet avec C++

78
ostream& manipulateur(argument);

LES LIBRAIRIES

Les principaux manipulateurs paramtriques sont reprsents Tableau4. Tableau 4 : principaux manipulateurs paramtriques Manipulateur Utilisation Action setbase(int) Entre/Sortie Dfinit la base de conversion setprecision(int) Entre/Sortie Dfinit la prcision de sortie des nombres en virgule flottante setw(int) Entre/Sortie Dfinit le gabarit. Attention! Il retombe zro aprs chaque conversion !

3.5. ASSOCIATION DUN FLOT A UN FICHIER


Drivs de ostream, respectivement de istream, les classes ofstream et ifstream permettent la cration de flts de sortie ou dentre associs des fichiers : ofstream of(char *fileName, char openMode=ios:out); ifstream if(char *fileName, char openMode=ios:in); Le pointeur dcriture (respectivement de lecture) peut tre manipul au moyen de : seekp(int displacement, int relativeTo); respectivement : seekg(int displacement, int relativeTo); Par dfaut, relativeTo prend la valeur ios::begin, cest--dire que le dplacement se fera par rapport au dbut du fichier. Les autres valeurs possibles sont ios::current (dplacement relatif la position actuelle) et ios::end (dplacement par rapport la fin du fichier. Fermer un ofstream ou un ifstream requiert dans tous les cas lutilisation de close(); noter que dtruire une instance de flot dentre-sortie (delete) ne dtruit pas le fichier associ, mais gnralement le ferme (au cas o il tait rest ouvert). Dans tous les cas, il vaut mieux fermer explicitement un flot associ un fichier lorsque ce dernier nest plus utilis. Lutilisation des classes ifstream et ofstream requiert linclusion de fstream.h; fstream. h incluant iostream.h, il nest en principe pas ncessaire de linclure nouveau explicitement. Le fichier peut tre ouvert dans diffrents modes, selon la valeur du paramtre openMode, comme dcrit dans le Tableau5 : Tableau 5. Modes douverture dun fichier Bit de mode douverture Action ios::in Ouverture en lecture (obligatoire pour ifstream) ios::out Ouverture en criture (obligatoire pour ofstream) ios::app Ouverture en mode ajout (ofstream seulement) ios::ate Place le pointeur fichier en fin de fichier aprs ouverture ios::trunc Si le fichier existe, son contenu est dtruit aprs ouverture ios::nocreate Le fichier doit exister louverture (ne doit pas tre cre) ios::noreplace Le fichier ne doit pas exister louverture (sauf si ios::ate ou ios::app est spcifi) Drivant de ifstream et ofstream, un flot de type fstream peut tre associ un fichier utilisable simultanment en lecture et en criture.

4.

L++ (STANDARD COMPONENTS)

L++ est une tentative de correction de lerreur commise par les concepteurs de C++, qui nont pas dfini de librairie standard C++ ( lexception de iostream). L++ contient des fonctions trs gnrales, universellement applicables. L++ est livr en standard avec les compilateurs conformes la spcification Cfront de USL, mais nest actuellement pas prvu pour la standardisation ANSI. L++ se trouve sur la grande majorit des compilateurs UNIX, mais nest gnralement pas inclus dans les versions pour ordinateurs personnels (Symantec, Microsoft ou Borland). Cest fort regrettable, car L++ propose un ensemble de fonctions trs puissant et universellement applicable, linverse des librairies proposes sur PC, qui ne concernent souvent que des portione limites de linterface utilisateur spcifique la machine utilise. Parmi les classes proposes par L++, citons : Bit : Permet la dfinition et la manipulation de chanes de bits de longueur arbitraire Block : Gestion de zones mmoires Graph : Structure de graphes (lments relis par des rseaux arbitraires) List : Listes gnralises. Map : Gestion de tableaux adressage multiple, en particulier avec adressage relatif au contenu. Pool : Gestion de mmoire usage gnral, avec rallocation dynamique de bloca devenus

Conception et programmation oriente objet avec C++

79

LES LIBRAIRIES
libres. Regexp : Manipulation dexpressions rgulires. Set : Manipulation densembles. Stopwatch : Chronomtre. String : Gestion de chanes de caractres dynamiques. Utilise Pool. Symbol : Gestion de tables de symboles. Utilise Pool. Time : Manipulation et contrle de donnes associes aux temps. bag : Container dinformation gnralis. Il est possible de faire des oprations dentresortie sur des bags. g2++ : Routines dencodage et dcodage de donnes. g++ permet la transmission dinformation entre ordinateurs diffrents sans prcautions relativement la manire dencodage propre chaque machine. Ainsi, pour transfrer un entier dans sa reprsentation binaire entre un PowerPC et un CPU Intel, il est normalement ncessaire de tenir compte de la reprsentation diffrente des entiers dans le stack du PowerPC et du chip Intel. Lutilisation de g2++ permet dviter cet inconvnient en introduisant la notion de syntaxe de transfert, un peu la manire de ASN.1 dans le monde OSI, ou IDL / XDR dans le monde RPC.

5.

QUELQUES AUTRES LIBRAIRIES

Il existe de nombreuses autres librairies, certaines dpendantes du systme dexploitation, dautres indpendantes. Certaines ne sont que des librairies C avec un interface C++, dautres sont des librairies natives. Il serait inutile et vain de chercher faire un listing exhaustif. Nous nous bornerons citer quelques-unes des plus intressantes : Motif++ : Version C++ de Motif 1.2. Domaine public. Devrait tre bientt remplace par Motif2.0, qui devrait comporter un interface C++ en mode natif. Interviews : Librairie originellement dveloppe Stanford, est actuellement implmente sur plusieurs plate-formes, y compris Motif et Macintosh. Emule Motif sans faire explicitement appel Motif. Microsoft Foundation Classes : Librairie daccs Windows. Dans sa dernire mouture, avec Visual C++ 4.0, est devenue multi-plateformes. Il est possible de gnrer du code pour Alpha, Intel, PowerPC et Macintosh, avec une librairie native. Think C Library : librairie fournie avec le compilateur Think C (Symantec C++) pour le Macintosh. La librairie nest pas crite en C++, mais dispose dun interface C++. DCE++ : Actuellement en domaine semi-public, DCE++ pourrait tre standardise dans un proche avenir. DCE++ facilite lutilisation de DCE (Distributed Computing Environment ) en C++. Laccs des services distribus comme DTS (Distributed Time Service), RPC (Remote Procedure Call), NIS (Network Information Service) ou DNS (Domain Name Service) est encapsul dans des classes facilement utilisables. DCE++ est distribu par HaL computers (http://hal.com). GCOOL : Domaine public. Implmente des classes universellement utilisables, un peu la manire de L++. Pour les intresss, il existe sur Internet une rubrique (en fait, il en existe plusieurs qui se rfrencent les unes les autres) rassemblant les librairies C++, tant du domaine public que commerciales. Cette rubrique se nomme FAQ : available C++ libraries et peut tre consulte par ftp ou par http (World Wide Web). La mise jour se fait environ une fois par mois, et est raisonnablement exhaustive. Comme beaucoup de rubriques sur Internet, celle-ci dpend entirement de la disponibilit de son auteur bnvole. Actuellement (octobre 1995) la rubrique comprend 50 pages et va de librairies mathmatiques (LINPACK++, FFT++) des classes couvrant la biologie et lastrophysique, en passant par de trs intressantes librairies de classes gnriques et de classes utilisables pour la gnration dinterfaces utilisateur. La plupart de ces classes sont dveloppes pour UNIX, mais la disponibilit du code source pour beaucoup dentre elles les rend utilisables aussi dans dautres environnements (Windows 95 et Windows NT entre autres). Il est galement possible dutiliser des sites Internet spcialiss (www.apple.com, www.microsoft.com, www.hal.com, www.att.com, www.borland.com, etc...) pour se renseigner sur la disponibilit de librairies. Il est de toutes faons recommnad, avant dentreprendre un nouveau projet, de se renseigner sur les librairies disponibles. Mme si, pour des raisons de licences ou de copyright, ou simplement derreurs, elles se rvlent inutilisables, il est trs utile de connatre dautres solutions un mme problme : dans loptique de la rutilisation de logiciels, mme les erreurs (?) des autres peuvent tre mises profit.

Conception et programmation oriente objet avec C++

ANNALES

Conception et programmation oriente objet avec C++

81

1re SESSION 2002/2003

1ERE SESSION 2002/2003


Date : 11 juin 2003. Dure : 3 heures. Documents : Le cours.

1.

EXERCICE 1 : QUESTIONS A CHOIX MULTIPLE

Conception et programmation oriente objet avec C++