La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

ENIG GCR1 Programmation en C++ Amira Mekki Janvier 2009.

Présentations similaires


Présentation au sujet: "ENIG GCR1 Programmation en C++ Amira Mekki Janvier 2009."— Transcription de la présentation:

1 ENIG GCR1 Programmation en C++ Amira Mekki Janvier 2009

2 Entrées-sorties simples
Cette section traite de l'utilisation simple des flux standard d'entrée-sortie, c'est-à-dire la manière de faire en C++ les opérations qu'on fait habituellement en C avec les fonctions printf et scanf. Un programme qui utilise les flux standard d'entrée-sortie doit comporter la directive #include <iostream.h> ou bien, si vous utilisez un compilateur récent et que vous suivez de près les recommandations de la norme4 : #include <iostream> using namespace std;

3 Entrées-sorties simples
Les flux d'entrée-sortie sont représentés dans les programmes par les trois variables, pré déclarées et pré initialisées, suivantes : Cin: le flux standard d'entrée Cout: le flux standard de sortie Cerr: le flux standard pour la sortie des messages d'erreur

4 Entrées-sorties simples
Les écritures et lectures sur ces unités ne se font pas en appelant des fonctions, mais à l'aide des opérateurs << appelé opérateur d'injection ( injection de données dans un flux de sortie), >> appelé opérateur d'extraction ( extraction de données d'un flux d'entrée).

5 Entrées-sorties simples
cout << expression à écrire le résultat de cette expression est l'objet cout lui-même. On peut donc lui injecter une autre donnée, puis encore une, etc. : cout << expression << expression << expression

6 Un exemple L’inévitable hello world: #include <iostream>
using namespace std ; void main ( ) { cout << ” hello world ! ” << endl ; }

7 Exemple : programme C++ simple
/* texte source (compt.cpp) d'un programme comptant le nombre de lignes du fichier texte lu sur l'entrée standard (utilisation des classes d'E/S standard*/ #include <iostream> // lecture des interfaces des classes d'E/S using namespace std ; Void main() //programme principal = fonction sans arguments { char carc; int nombreligne=0; while(cin.get(carac)!='# ') // tant que l'on n'a pas lu tout le texte à // partir du //flot d'entrée standard "cin" { if (carac=='\n') //si c'est une fin de ligne, on ++nombreligne; // incrémente le nombre de ligne } cout<<nombreligne<<"lignes\n"; //affichage du résultat sur le flot de sortie standard "cout"

8 Entrées / Sorties (I) C C++ #include <stdio.h>
#include <iostream> #include <fstream> #include <strstream> printf --> standard output scanf <-- standard input fprintf --> FILE* fscanf <-- FILE* cout --> standard output cerr --> standard error output cin <-- standard input ofstream --> output file ifstream <-- input file ostream& operator<< istream& operator>>

9 Allocation mémoire C C++ int* var = new int( value );
int* var = (int*)malloc(sizeof(int)); *var = value; int* array = (int*)malloc(n*sizeof(int)); C++ int* var = new int( value ); int* array = new int[10]; En C++, les allocations sont typées.

10 Désallocation mémoire
int* var = (int*)malloc(sizeof(int)); int* array = (int*)malloc(n*sizeof(int)); free( var ); free( array ); C++ int* var = new int(); int* array = new int[10]; delete var; delete [] array;

11 Définition des classes
Tous les membres d'une classe doivent être au moins déclarés à l'intérieur de la formule class nom { //les membres déclarés ici sont privés public: //les membres déclarés ici sont publics private: //etc. }; qui constitue la déclaration de la classe.

12 Les expressions public: et private: peuvent apparaître un nombre quelconque de fois dans une classe.
Les membres déclarés après private: (resp. public:) sont privés (resp. publics) jusqu‘à la fin de la classe, ou jusqu‘à la rencontre d'une expression public: (resp. private:). Un membre public d'une classe peut être accédé partout où il est visible ; un membre privé ne peut être accédé que depuis une fonction membre de la classe

13 Définition des classes Exemple
class Point { public: void afficher() { cout << '(' << x << ',' << y << ')'; } void placer(int a, int b) { //validation des valeurs de a et b; x = a; y = b; private: int x, y; };

14 Accès aux membres Accès aux membres d'un objet
On accède aux membres des objets en C++ comme on accède aux membres des structures en C. Par exemple, à la suite de la définition de la classe Point donnée précédemment on peut déclarer des variables de cette classe en écrivant : Point a, b, *pt; // deux points et un pointeur de point

15 Accès aux membres Accès aux membres d'un objet
Dans un contexte où le droit de faire un tel accès est acquis l'accès aux membres du point a s‘écrit : a.x = 0; // un accès bien écrit au membre x du point a dans le cas ou x est public d = a. placer(10,20); // un appel bien écrit de la fonction distance de l'objet a

16 Si on suppose que le pointeur pt a été initialisé, par exemple par une expression telle que
pt = new Point; // allocation dynamique d'un point alors des accès analogues aux précédents s‘écrivent : pt->x = 0; // un accès bien écrit au membre x du point pointé par pt d = pt-> placer(10,20); // un appel de la fonction distance de l'objet pointé par pt

17 class Point { public: void afficher() { cout << '(' << x << ',' << y << ')'; } void placer(int a, int b) { //validation des valeurs de a et b; x = a; y = b; double distance(Point autrePoint) { int dx = x - autrePoint.x; int dy = y - autrePoint.y; return sqrt(dx * dx + dy * dy); private: int x, y; };

18 Définition des classes
Cependant, dans le cas des fonctions, aussi bien publiques que privées, on peut se limiter à n‘écrire que leur en-tête à l'intérieur de la classe et définir le corps ailleurs, plus loin dans le même fichier ou bien dans un autre fichier. Il faut alors un moyen pour indiquer qu'une définition de fonction, écrite en dehors de toute classe, est en réalité la définition d'une fonction membre d'une classe. Ce moyen est l'opérateur de résolution de portée, dont la syntaxe est NomDeClasse::

19 Définition des classes
Par exemple, voici notre classe Point avec la fonction distance définie séparément : class Point { public: ... double distance(Point autrePoint); } Il faut alors, plus loin dans le même fichier ou bien dans un autre fichier, donner la définition de la fonction promise dans la classe Point. Cela s‘écrit : double Point::distance(Point autrePoint) { int dx = x - autrePoint.x; int dy = y - autrePoint.y; return sqrt(dx * dx + dy * dy); }; Point.h Point.cpp

20 L'interface de la classe (« Point.h") contient
les déclarations des méthodes de la classe. (indispensable pour le client) Les déclarations des attributs (en général, intitules au client donc inaccessibles) La réalisation de la classe (« Point.cpp") contient : Les définitions des méthodes qui n'ont été que déclarées dans l'interface de la classe.

21 EXEMPLE point.cpp Point.h #include "Point.H" #include <iostream>
using namespace std ; #include <math.h> void Point::Afficher() { cout<< "( " << x<<","<<y<<")"<<endl; }; void Point :: placer(int a, int b) {x = a; y = b; double Point::distance(Point autrePoint) { int dx = x - autrePoint.x; int dy = y - autrePoint.y; return sqrt(dx * dx + dy * dy); class Point { public: void Afficher (); void placer(int a, int b); double distance(Point autrePoint); private : int x,y; };

22 Test des méthodes de la classe Point
MainPoint.cpp #include "Point.H" #include <iostream> using namespace std ; void main ( ) { //declaration Point pt1; Point pt2; //Affectation des valeurs pour les deux points pt1.placer(1,1); pt2.placer(5,10); //Affichage des coordonnées pour les points pt1.Afficher(); pt2.Afficher(); // distance entre deux points double d=pt2.distance(pt1); cout <<" la distance entre les deux points est "<< d <<endl; }

23 Méthodes particulière : constructeur d'objet
Un constructeur d'une classe est une fonction membre spéciale qui : a le même nom que la classe n'indique pas de type de retour ne contient pas d'instruction return Le rôle d'un constructeur est d'initialiser un objet, notamment en donnant des valeurs à ses données membres. Le constructeur n'a pas à s'occuper de trouver l'espace pour l'objet ; il est appelé (immédiatement) après que cet espace ait été obtenu, et cela quelle que soit la sorte d'allocation qui a été faite : statique, automatique ou dynamique, cela ne regarde pas le constructeur.

24 Exemple class Point { public: Point(int a, int b) {
validation des valeurs de a et b x = a; y = b; } ... autres fonctions membres ... private: int x, y; };

25 Une classe peut posséder plusieurs constructeurs, qui doivent alors avoir des signatures différentes : class Point { public: Point(int a, int b) { validation de a et b x = a; y = b; } Point(int a) { validation de a x = a; y = 0; Point() { x = y = 0; ... private: int x, y; };

26 Point p(4,5); //appel de Point(4,5)
Exemple: la classe Point à un constructeur Point(int,int) Point p(4,5); //appel de Point(4,5) Point * courant = new Point(3,2); //appel de Point(3,2) // Supposons que la classe PERSONNE ait un constructeur // PERSONNE(char *); PERSONNE patron("Dupont");

27 Point::Point(int a, int b) { //validation de a et b x = a; y = b; }
point.cpp Point.h #include "Point.h" Point::Point(int a, int b) { //validation de a et b x = a; y = b; } class Point { public: Point(int a = 0, int b = 0); ... private: int x, y; };

28 Destructeurs De la même manière qu'il y a des choses à faire pour initialiser un objet qui commence à exister, il y a parfois des dispositions à prendre lorsqu'un objet va disparaître. Un destructeur est une fonction membre spéciale. Il a le même nom que la classe, précédé du caractère ~. Il n'a pas de paramètre, ni de type de retour. Il y a donc au plus un destructeur par classe.

29 Destructeurs Le destructeur d'une classe est appelé lorsqu'un objet de la classe est détruit, juste avant que la mémoire occupée par l'objet soit récupérée par le système. Exemple : class Point { ... ~Point () { delete [] label; } };

30 Synthèse du destructeur
Si le programmeur n'a pas écrit de destructeur pour une classe, le compilateur en synthétise un, de la manière suivante : si la classe n'a ni objets membres ni classes de base, alors il s'agit du destructeur trivial qui consiste à ne rien faire, si la classe a des classes de base ou des objets membres, le destructeur synthétisé consiste à appeler les destructeurs des données membres et des classes de base, dans l'ordre inverse de l'appel des constructeurs correspondants.

31 EXERCICE1 « M. Holly Pierre est né en 1965 »
Ecrire une classe Personne permettant de décrire complètement une personne, sachant que l'on souhaite avoir autant d'informations que dans la phrase suivante : « M. Holly Pierre est né en 1965 » Pour cela la classe doit contenir - un constructeur à la classe Personne. - une méthode de nom retourneInfos. Cette méthode doit afficher une chaîne de caractères similaire à la phrase donnée precedament Ecrire un programme Main de test de la classe qui déclare 3 variables de type Personne, crée 2 instances de personne pour les affecter dans les variables et affiche les informations les concernant

32 EXERCICE2 Écrire un programme qui calcule la note finale d'un étudiant. Le programme demandera le nom de l'étudiant puis sa note de partiel, sa note de l'exam final et son ensemble de notes de devoirs maisons. Il affichera ensuite le résultat tel que la note de partiel compte pour 20% , l'examen pour 40% et la moyenne des devoirs pour 40% de la note nale.

33 Paramètre d'une méthode
Une méthode peut avoir comme paramètres (éventuellement préfixés par const) des valeurs ou références d'objet de type primitif, pointeur ou classe. Toute méthode a un argument implicite, qui est un pointeur sur l'objet sur lequel elle s'applique, de nom this On ajoute const à la fin de la déclaration de la méthode si elle ne modifie pas les attributs de l'objet auquel on l'applique.

34 Déclaration des paramètres
On déclare les paramètres dans une liste, éventuellement vide, déclarations séparées par une virgule. Chaque déclaration est de la forme : [const]typeParam [&] nomParametre Le préfixe const signifie que l'argument n'est pas modifié par la méthode. & signifie que le passage est fait par référence, sinon le passage est effectué par valeur, c'est-à-dire par copie de la valeur de l'argument dans le paramètre local. Les noms des paramètres sont locaux à la méthode.

35 Exemple class Point { int x, y; public: int X() const { return x; }
Avec la déclaration de la classe, les fonctions X et Y sont sécurisées : sur un objet constant elles ne permettent que la consultation, sur un objet non constant elles permettent la consultation et la modification : class Point { int x, y; public: int X() const { return x; } int Y() const { return y; } int & X() { return x; } int& Y() { return y; } ... }; const Point a(2, 3); Point b(4,5); int r; ... r = a.X(); // Oui a.X() = r; // ERREUR ( a.X() rend une valeur) r = b.X(); // Oui b.X() = r; // Oui ( b.X() rend une r¶ef¶erence)

36 Membres statiques Chaque objet d'une classe possède son propre exemplaire de chaque membre ordinaire (bientôt nous dirons membre non statique) de la classe : pour les données membres, cela signifie que de la mémoire nouvelle est allouée lors de la création de chaque objet ; pour les fonctions membres, cela veut dire qu'elles ne peuvent être appelées qu'en association avec un objet (on n'appelle pas la fonction f mais la fonction f sur l'objet x ).

37 Membres statiques A l'opposé de cela, les membres statiques, signalés par la qualification static précédant leur déclaration, sont partagés par tous les objets de la classe. De chacun il n'existe qu'un seul exemplaire par classe, quel que soit le nombre d'objets de la classe. Les données et fonctions membres non statiques sont donc ce que dans d'autres langages orientés objets on appelle variables d'instance et méthodes d'instance, tandis que les données et fonctions statiques sont appelées dans ces langages variables de classe et méthodes de classe. La visibilité et les droits d'accès des membres statiques sont régis par les mêmes règles que les membres ordinaires.

38 Membres statiques class Point { int x, y; public:
static int nombreDePoints; Point(int a, int b) { x = a; y = b; nombreDePoints ++; } };

39 Membres statiques Chaque objet Point possède ses propres exemplaires des membres x et y mais, quel que soit le nombre de points existants à un moment donné, il existe un seul exemplaire du membre nombreDePoints. Initialisation. La ligne mentionnant nombreDePoints dans la classe Point est une simple annonce , comme une déclaration extern du langage C. Il faut encore créer et initialiser cette donnée membre (ce qui, pour une donnée membre non statique, est fait par le constructeur lors de la création de chaque objet).

40 Membres statiques Cela se fait par une formule analogue à une définition de variable, écrite dans la portée globale, même s'il s'agit de membres privés : int Point::nombreDePoints = 0; (la ligne ci-dessus doit être écrite dans un fichier .cpp , non dans un fichier .h ) L'accès à un membre statique depuis une fonction membre de la même classe s‘écrit comme l'accµes µa un membre ordinaire (voyez l'accès à nombreDePoints fait dans le constructeur Point). L'accès à un membre statique depuis une fonction non membre peut se faire à travers un objet, n'importe lequel, de la classe : Point a, b, c; cout << a.nombreDePoints << "\n";

41 Fonctions membres statiques
Une fonction membre statique n'est pas attachée à un objet. Par conséquent : elle ne dispose pas du pointeur this de sa classe, elle ne peut référencer que les fonctions et les membres statiques.

42 static int nombreDePoints; public: static int combien() {
Par exemple, voici la classe Point précédente, dans laquelle le membre nombreDePoints a été rendu privé pour en empêcher toute modification intempestive. Il faut donc fournir une fonction pour en consulter la valeur, nous l'avons appelée combien : class Point { int x, y; static int nombreDePoints; public: static int combien() { return nombreDePoints; } Point(int a, int b) { x = a; y = b; nombreDePoints ++; }; Pour afficher le nombre de points existants on devra maintenant écrire une expression comme (a étant de type Point) : cout << a.combien() << "\n";

43 static int nombreDePoints; public: Point(int a, int b);
Point.h Point.cpp class Point { int x, y; static int nombreDePoints; public: Point(int a, int b); static int combien() { return nombreDePoints; } }; #include "Point.H" int Point::nombreDePoints = 0; Point::Point(int a, int b) { //validation de a et b x = a; y = b; nombreDePoints++; }; #include "Point.H" #include <iostream> using namespace std ; void main ( ) { Point p1(2,3); Point p2(2,1); cout<<"val1 "<<p1.combien()<<endl; cout<<"val2 "<<p2.combien()<<endl; }

44 Fonctions Amies

45 Fonctions amies La notion de "fonction amie" propose une solution intéressante, sous la forme d'un compromis entre encapsulation formelles des données privées et des données publiques. Lors de la définition d'une classe, il est en effet possible de déclarer qu'une ou plusieurs fonctions (extérieur de la classe) sont des "amies", une telle déclaration d'amitié les autorise alors à accéder aux donnés privées, au même titre que n'importe qu'elle fonction membre.

46 Fonctions amies Il existe plusieurs situations d'amitiés :
Fonction indépendante amie d'une classe Fonction membre d'une classe, amie d'une autre classe Fonction amie de plusieurs classes Toutes les fonctions membre d'une classe amie d'une autre classe.

47 Fonctions amies Exemple de fonction indépendante amie d'une classe :
Soit la fonction coïncide amie de la classe Point (chargée de détecter la coïncidence éventuelle de deux points). class Point { int x,y; public : Point (int abs=0; int ord=0){x=abs; y=ord;} friend int Coincide(Point, Point); };

48 Fonctions amies int Coincide(Point p, Point q)
{ if ((p.x==q.x) && (p.y==q.y)) return 1; else return 0; } void main() { Point a(1,0), b(1,2); if (Coincide(a,b)) cout<<"a coincide avec b"<<endl; cout<<"a et b sont différents"<<endl;

49 Fonctions amies Fonction membre d'une classe, amie d'une autre classe
Il suffit de préciser, dans la déclaration d'amitié, la classe à laquelle la fonction concernée, à l'aide de l'opérateur de résolution de portée (::) class A { // partie privée // partie publique friend int B::f(char, A); }; // f doit pouvoir accéder aux //membres privés de A elle sera //déclaré amie au sein de la classe. class A; class B { … int f(char,A); }; int B::f(char …, A …) { // on a accès ici aux //membres privés de tout //objet de type A }

50 Fonctions amies Fonction amie de plusieurs classes : class A {
// partie privée // partie publique friend int B::f(char, A); }; // f doit pouvoir accéder aux //membres privés de A elle sera //déclaré amie au sein de la classe. class A; class B { … int f(char,A); }; int B::f(char …, A …) { // on a accès ici aux //membres privés de tout //objet de type A }

51 Fonctions amies Fonction amie de plusieurs classes : class B; class A
{ // partie privée // partie publique friend void f(A, B); }; class A; class B { // partie privée // partie publique friend void f(A, B); };

52 Surcharge des opérateurs

53 Opérateurs Mathématiques : +, -, *, /, %, ++, --
Logiques : &&, ||, !, ==, !=, <, >, <=, >= Données : *, &, -> Binaire : &, |, ^, ~, <<, >> Assignation : =, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^= Tous surchargeables.

54 En C++ on peut redéfinir la sémantique des opérateurs du langage, soit pour les étendre à des objets, alors qui n‘étaient initialement définis que sur des types primitifs, soit pour changer l‘éffet d'opérateurs prédéfinis sur des objets. Cela s'appelle surcharger des opérateurs. Il n'est pas possible d'inventer de nouveaux opérateurs ; seuls des opérateurs déjà connus du compilateur peuvent être surchargés. Tous les opérateurs de C++ peuvent être surchargés, sauf les cinq suivants :

55 Par exemple, la sémantique d'une surcharge de ++ ou <= n'a pas à être liée avec celle de + ou <. Surcharger un opérateur revient à définir une fonction ; tout ce qui a été dit à propos de la surcharge des fonctions s'applique donc à la surcharge des opérateurs. Plus précisément, pour surcharger un opérateur (ce signe représente un opérateur quelconque) il faut définir une fonction nommée opérator .Ce peut être une fonction membre d'une classe ou bien une fonction indépendante. Si elle n'est pas membre d'une classe, alors elle doit avoir au moins un paramètre d'un type classe.

56 Surcharge d'un opérateur par une fonction membre
Si la fonction operator est membre d'une classe, elle doit comporter un paramètre de moins que la pluralité de l'opérateur : le premier opérande sera l'objet à travers lequel la fonction a été appelée. Ainsi, sauf quelques exceptions : « obj » ou « obj » équivalent à obj.operator () «obj1 obj2 » équivaut à obj1.operator (obj2)

57 int X() const { return x; } int Y() const { return y; }
class Point { int x, y; public: Point(int = 0, int = 0); int X() const { return x; } int Y() const { return y; } Point operator+(const Point) const; //surcharge de + par une fonction membre ... }; Point Point::operator+(const Point q) const { return Point(x + q.x, y + q.y); } Point p, q, r; ... r = p + q; // compris comme : r = p.operator+(q);

58 Exercice 4 redéfinir l’opérateur == correspondant à la fonction coïncide.

59 Correction4 // Surcharge de l'opérateur == class point { private:
int x,y; public: point(int abs,int ord); // déclaration de la fonction amie friend int operator==(point,point); }; #include "Point.h" point::point(int abs,int ord) { x=abs; y=ord;}

60 #include"Point.h" #include <iostream> using namespace std; int operator ==(point p, point q) { if((p.x==q.x)&&(p.y==q.y)) return 1; else return 0; } void main() point a(4,0),b(4,0),c(0,0); if(a==b)cout<<"a coïncide avec b\n"; else cout<<"a est différent de b\n"; if(a==c)cout<<"a coïncide avec c\n"; else cout<<"a est différent de c\n";

61 Exercice 5 En utilisant la propriété de surcharge des fonctions
du C++, créer - une fonction membre de la classe vecteur de prototype float vecteur::operator*(vecteur); qui retourne le produit scalaire de 2 vecteurs vecteur vecteur::operator*(float); qui retourne le vecteur produit d’un vecteur et d’un réel (donne une signification à v2 = v1 * h;) - une fonction AMIE de la classe vecteur de prototype vecteur operator*(float, vecteur); qui retourne le vecteur produit d’un réel et d’un vecteur (donne une signification à v2 = h * v1;)

62 On doit donc pouvoir écrire dans le programme:
vecteur v1, v2, v3, v4; float h, p; p = v1 * v2; v3 = h * v1; v4 = v1 * h; Remarque: On aurait pu remplacer la fonction membre de prototype vecteur vecteur::operator*(float); par une fonction AMIE de prototype vecteur operator*(vecteur, float);

63 Correction 5 Vecteur.h class vecteur { private: float x,y; public:
vecteur(float,float); void affiche(); // surcharger + vecteur operator+(vecteur); // surcharger * : produit scalaire float operator*(vecteur); // surcharger * : vecteur (passé en paramètre)*scalaire retourné vecteur operator*(float); // surcharger * : vecteur (objet)*scalaire retourné friend vecteur operator*(float,vecteur); };

64 #include "vecteur.h" #include <iostream> using namespace std; vecteur::vecteur(float abs =0,float ord = 0) {x=abs;y=ord;} void vecteur::affiche() {cout<<"x = "<<x<<" y = "<<y<<"\n";} vecteur vecteur::operator+(vecteur v) {vecteur res(0,0); res.x = v.x + x; res.y = v.y + y; return res;} float vecteur::operator*(vecteur v) {float res = v.x * x + v.y * y; vecteur vecteur::operator*(float f) {vecteur res(0,0); res.x = f*x; res.y = f*y; return res; }

65 #include "vecteur.h" #include <iostream> using namespace std; vecteur operator*(float f, vecteur v) { v.x = f*v.x; v.y = f*v.y; return v; } void main() vecteur a(2,6),b(4,8),c(0,0),d(0,0); float p,h=2.0; p = a * b; cout<< p <<"\n"; c = h * a; c.affiche(); d = a * h; d.affiche();

66 CAS PARTICULIERS DES OPÉRATEURS D’INSERTION (<<) ET D’EXTRACTION DE FLUX (>>)
Dans le langage C++ nous avons l’opérateur (<<) pour afficher en sortie, et l’opérateur (>>) pour saisir les entrées. Ces opérateurs ont été surchargés, fournis dans une classe de librairie classique (iostream.h) qui vient avec chaque compilateur C++

67 Normalement dans le langage C, ces opérateurs servent juste pour la décalage à gauche (<<) et le décalage à droite (>>) dans des manipulations bit-à-bit sur des entiers et des chars. Or avec un compilateur C++, on étendu le rôle des ces opérateurs pour remplacer les fonctions fastidieuses d’écriture à l’écran avec printf, et de saisie avec scanf, qui exigent de fournir précisément le format pour chaque type de donnée à afficher ou à saisir.

68 Malgré cela, même si la surcharge a été effectuée dans la librairie pour reconnaître la plupart des types de données de base comme les entiers (int), les virgule flottantes (float), et les chaînes de caractère (char*), le constructeur de la librairie ne peut pas deviner le type d’objet que vous allez créer plus tard et sur lequel va opérérer l’affichage ou la saisie. Aussi, c’est à vous que revient le rôle d’instruire ces opérateurs du comment procéder avec votre type d’objet.

69 La classe que vous créez contient alors la déclaration des fonctions d’insertion de flux ostream et d’extraction istream qui deviennent des fonctions amies de la classe: Class nom_de_la_classe { .... friend ostream &operator<<(ostream&, const nom_de_la_classe &); friend istream &operator>>(istream&, nom_de_la_classe &); } Lorsque le compilateur identifiera la séquence: (objet de type ostream) << (objet de type nom_de_la_classe) Il invoquera la fonction définie dans votre classe nom_de_la_classe::operator<<()

70 Exemple #include <iostream> using namespace std; class Point {
double x, y; public: Point(double a, double b); Point operator+( Point rhs) ; friend ostream& operator<<(ostream& os, Point& c); friend istream& operator>>(istream& is, Point& c); };

71 #include "Point.H" Point::Point(double a, double b) { x=a; y=b; } Point Point::operator+(Point rhs) { return Point(x + rhs.x, y + rhs.y);

72 #include "Point.H" #include <iostream> using namespace std; ostream& operator<<(ostream& os, Point& c) { os<<"("<<c.x<<" , "<<c.y<<")"; return os; } istream& operator>>(istream& is, Point& c) is>>c.x>>c.y; return is;} void main() Point A(12.347, 15), B(-2, 5.45), Result(0,0); Result=A+B; cout<<Result<<endl;

73 CAS PARTICULIER DE L’OPÉRATEUR D’ASSIGNATION (=)
#include "Point.h" Point:: Point(int a, int b) {x=a; y=b; } Point Point:: operator=(Point p) { this->x=p.x; this->y=p.y; return (*this); #include <iostream> using namespace std; class Point { public : int x ,y; Point(int, int); Point operator=(Point p) ; }; #include "Point.h" #include <iostream> using namespace std; void main() { Point p1(4,7); Point p2(0,0); p2=p1; cout << p2.x<<"et"<<p2.y; }

74 La classe String

75 Héritage

76 Généralités sur l'héritage
De nombreuse classes peuvent être conçues comme des spécialisation de classes plus générales (relation EstUn ou SorteDe). L'héritage permet d'éviter de redéfinir dans une classe dérivée le comportement des classes ancêtre, et donc, de ne se préoccuper que de comportement particulier à la classe. On organise les classes selon une hiérarchie (arbre d'héritage ou graphe si héritage multiple).

77 Généralités sur l'héritage (suite)
Sémantique de l'héritage si on a A …  B (B hérite de A) alors B doit pouvoir s'employer partout où A est employé : principe de SUBSTITUTION Sous typage Les descendants d'une classe en sont des sous-types Si on a ABC …, tout objet instance d'une classe héritant de A (donc de classe A,B,C, …) est de "type A". On peut lui appliquer toutes les opérations définies dans la classe A. Noter qu'un objet peut être de "type A" sans être une instance d'une classe héritant de A.

78 Exemple d'arbre d'héritage
Séquence Pile Collection Nom séquentielle Dictionnaire Ensemble

79 Arbre d'héritage (autre exemple)
Ligne Forme Rectangle Cercle Ellipse Carré Principe de substitution : toute opération applicable à une instance de Forme doit être applicable à une instance de Ligne, Ellipse, Cercle, …

80 L'héritage en C++ class classeDérivée : [mode] classeDeBase {
//complément d'interface pour "classeDérivée" } ; mode = public  cas le plus fréquent = private  pour héritage partiel(par défaut) = protected  les membre publics seront considérés comme protégés Héritage multiple : class A : public B, public C {… … …};

81 Exemple d'héritage class Pixel:public Point //un pixel est un point
// définition de la classe pixel par dérivation de la classe point class Pixel:public Point //un pixel est un point // ou une sorte de point {public : enum Couleur {NOIR,ROUGE,BLANC}; Pixel(Couleur laCouleur, int abs, int ord); //la construction d'un pixel s'appuie sur la construction d'un Point void Colorer (Couleur laCouleur = NOIR) { coul=laCouleur;} protected : Couleur coul; };

82 Appels des Constructeurs /destructeurs
Pour un objet de classe C A la création Classe A Classe B Classe C Appel de A() Puis de B() Puis de C() Appel de ~C() Puis de ~B() Puis de ~A() A la destruction Héritage Simple

83 Appels des Constructeurs /destructeurs
ClasseC : public classeA, public classeB ClasseA Classe B Classe C A la création Appel de A() Puis de B() Puis de C() A la destruction Appel de ~C() Puis de ~B() Puis de ~A() Héritage Multiple

84 Liaison entre constructeurs
Si le constructeur de la superclasse à des arguments, on doit préciser, avant le corps des constructeurs des classes dérivées (dans l'interface si "inline", sinon dans la réalisation de la classe), quels arguments lui transmettre, avec une syntaxe similaire à l'initialisation des attributs Exemple : class Pixel : public Point { public : // … Pixel (Couleur lacouleur, int abs=0, int ord =0) :Point(abs,ord), coul(lacouleur){} //… //appel du constructeur // initialisation de l'attribut //de la super-class // de la classe dérivée };

85 Exemples d'héritage #include "Point.h" class Forme { public :
void Deplacer (Point vecteur); void Dessiner () const; Forme (Point orig) : origine(orig) {}; protected : Point origine; };

86 Exemples d'héritage { public : void Dessiner() const; // redéfinition
class Rectangle : public Forme //un rectangle est une Forme { public : void Dessiner() const; // redéfinition Rectangle (Point basGauche, long longueur, long hauteur) : Forme(basGauche), diagonale(longeur, hauteur) {}; protected : Point diagonale; //attribut supplémentaire }; class Carre:public Rectangle //un carré est un rectangle {public : Carre(Point orig, long cote) : Rectangle(orig,cote,cote){}; }; //pas d'attribut ni d'autre méthode spécifié à carre

87 Visibilité des éléments hérités
Le mode d'héritage conditionne la visibilité, dans la classe dérivée, des éléments (attributs et méthodes) hérités de la superclasse. Héritage public : accès aux "public" et aux "protected" Héritage private : tout les éléments deviennent "private", mais on peut indiquer explicitement les éléments "public" que l'on souhaite laisser "public", donc accessibles aux clients de la classe dérivée. Héritage protected : les éléments "public" deviennent "protected", les autres sont inchangés

88 Affectations d'objets Point (int abs, int ord);
/* supposons que la classe Point soit munie d'un constructeur Point (int abs, int ord); et que la classe Pixel qui hérite de Point ait un constructeur Pixel (Couleur laCouleur, int abs, int ord); */ Point p(1,2); Pixel px( Pixel :: VERT, 3,5); p=px; //autorisé, affectation partielle // p demeure un Point; p est en (3,5) // Noter que le type couleur étant défini dans l'espace de // noms de Pixel, on doit préciser cette appartenance dans // l'écriture des valeurs de type Couleur, comme ici // pixel : :VERT

89 Affectations de pointeurs d'objets
Point p(1,2), *pp; Pixel *ppx; Pixel px(Pixel::VERT,3,5); pp=&px; //autorisé, car on peut affecter à un pointeur //de Point l'adresse d'un objet d'une classe //descendante, mais ppColorer(…); //est interdite ppx=&p; //de même ceci est interdit !

90 Spécialisation par redéfinition de méthodes
class Point { public : virtual void Afficher(); {cout <<x<<","<<y<<endl;} protected : int x,y; //x et y sont visibles des classes descendantes }; class Pixel:public Point { public : virtual void Afficher() //redéfinition de afficher {cout<<x<<""<<y<<"couleur:"<<coul<<endl;} //on aurait pu réutiliser la méthode de l'ancêtre, avec le corps suivant // { cout<<"couleur:"<<coul<<""; // Point::Afficher();}

91 Liaison statique/dynamique
Point * pt = new Point (2,6); Pixel px(Pixel::VERT, 3,5); ptAfficher(); // appel de la méthode Point::Afficher() pt=&px; ptAfficher(); //appel de la méthode pixel::Afficher() C'est pour obtenir ce fonctionnement (liaison dynamique), que l'on a placé l'attribut "virtual" devant la déclaration de la méthode dans l'interface de la classe de base : Virtual typeRetour NomMethode (listeParamétres); //NomMethode ne peut pas être redéfinie dans les descendant // qu'avec la même liste de paramètres et le même type de retour Si l'on ne précise pas l'attribut "virtuel" dans la classe de base, on aurait eu une liaison statique : appel de la méthode définie dans la classe de déclaration du pointeur.

92 Danger de la liaison statique
class Point {public : Point (int,int); void Afficher(); void Deplacer(int dx, int dy); {x+=dx; y+=dy; Afficher();} protected : int x,y; }; class Pixel:public Point {public : Pixel (Couleur,int,int); void Colorer(Couleur); protected : Couleur c; Point p(1,5); Pixel px(ROUGE, 4,8); p.Afficher(); // Affiche 1,5 Px.Afficher(); // Affiche 4,8 couleur:rouge p.Deplacer(1,1); // affiche 2,6 Px.Deplacer(1,1); // affiche 5,9 // car c'est la méthode Point::Afficher() qui à été appelée !!! // remède : virtual void Afficher() dans Point

93 Classe abstraites Le seul but de certaines classes est de servir uniquement de classes de base, et non d'être instanciables : on parle de classes abstraites (cas de Forme) En c++, une classe est considérée comme abstraite, si sa définition contient une méthode virtuelle pure ou son constructeur est déclaré protected. Exemple pour Forme, virtual void Dessiner()=0; Le compilateur c++ interdit d'instancier la classe Forme et vérifie que tous ces descendants redéfinissent la méthode virtual void Dessiner();

94 Forme canonique d'une classe
class T { public : // … autres méthodes T(); T & operator =(const T &); // affectation T(const T &); // constructeur de copie virtual ~T(); // destructeur private : … protected : … }; /* des lors qu'une fonction dispose de pointeurs sur des parties dynamiques, la copie d'objet de classe (aussi bien par le constructeur de recopie par défaut que par l'opérateur d'affectation) n'est pas satisfaisante. */

95 Création d'une classe simple par héritage d'un exemplaire de classe générique
//on peut combiner héritage et généricité. Exemple : Template<class T> //Point est une classe générique class Point { public : Point(T abs=O, T ord=0):x(abs), y(ord){} void Afficher(); protected : T x,y; }; class Pixel:public Point<int> //pixel hérite de l'exemplaire // Point<int> {public: Pixel(Couleur coul, int abs=0, int ord=0) :c(coul), Point<int>(abs,ord){} protected : Couleur c;

96 Création d'une classe générique par héritage
//on peut obtenir une classe générique par héritage d'une classe //Exemple : template<class T> //héritage d'une classe simple B class A:public B { //… }; template<class T> //héritage d'une classe générique class Vecteur:public Vect<T> {//…

97 Classe C++ : interface /** * A calendar date. */ class Date { public :
void set_date(int year,int month,int day ); void print() const; private : int year_; int month_; int day_; }; file.h

98 Classe C++ : implantation
file.cpp void Date::set_date(int year, int month,int day) { if (month == 2 && ! bisextile(year) && day > 28 ) { cerr << “Where did you see that\n” << “February could have “ << day << “ days “ << “in “ << year << “!” << endl; }

99 Constructeurs / Destructeurs
class Date { public : /** * Creates a Date from the year, month and day. * if parameters are not consistent, an error * message is produced. */ Date( int year, int month, int day ); /** Copy constructor */ Date( const Date& other_date ); /** Destroys this Date */ ~Date(); // … }; file.h


Télécharger ppt "ENIG GCR1 Programmation en C++ Amira Mekki Janvier 2009."

Présentations similaires


Annonces Google