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

Les opérateurs L’amitié Les opérateurs Introduction

Présentations similaires


Présentation au sujet: "Les opérateurs L’amitié Les opérateurs Introduction"— Transcription de la présentation:

1 Les opérateurs L’amitié Les opérateurs Introduction
Surcharge par fonction et par méthode Généralités Opérateurs arithmétiques et relationnels Opérateur d’affectation Opérateurs d’entrée/sortie Opérateur d’incrémentation et de décrémentation Autres opérateurs

2 L’amitié Toute fonction peut être déclarée «amie» d’une (ou plusieurs) classe(s) Une fonction « amie » d’une classe peut accéder directement (sans passer par des méthodes) aux données privées de la classe Exemple class Personne { public: ... friend void afficher(const Personne &); private: char *nom; int age; }; void afficher(const Personne &p) { cout << p.nom << p.age << endl; } La fonction afficher est «amie» de la classe Personne Elle accède aux données privées de la classe

3 Une classe peut aussi être déclarée «amie» d’une autre classe
Dans ce cas, toutes les méthodes de la classe « amie » peuvent accéder directement aux données privées de la classe Exemple class Personne { public: ... friend class Collect; private: char *nom; int age; }; class Collect { public: void AfficherNom() const; ... private: Personne tab[20]; int nb; }; void Collect::AfficherNom() const { for (int i=0; i<nb; i++) cout << tab[i].nom << endl; }

4 Les opérateurs Le C++ autorise la surcharge des opérateurs
L’objectif est de permettre au programmeur de fournir une notation plus conventionnelle et pratique que la notation fonctionnelle de base (par exemple, pour la manipulation d’objets arithmétiques complexes) Il existe 2 manières de surcharger un opérateur Un opérateur peut être surchargé par une fonction. Dans ce cas au moins une opérande doit être de type «classe». Un opérateur peut être surchargé par une méthode d’une classe. Dans ce cas, la première opérande est l’objet pour laquelle la méthode est invoquée.

5 Surcharge par une fonction
class Vecteur3d { public: Vecteur3d(int=0, int=0, int=0); int Get(int i); friend Vecteur3d operator+( const Vecteur3d&, const Vecteur3d&); private: int x, y, z; };

6 // constructeur Vecteur3d::Vecteur3d(int a, int b, int c) { x = a; y = b; z = c; } // recuperation d’une valeur int Vecteur3d::Get(int i){ switch (i) { case 0: return x; case 1: return y; case 2: return z; default : cout << "erreur de rang" << endl; return 0;

7 // Addition de 2 Vecteurs
int operator+( const Vecteur3d& v1, const Vecteur3d& v2) { Vecteur3d res; res.x = v1.x + v2.x; res.y = v1.y + v2.y; res.z = v1.z + v2.z; return res; }

8 La fonction (l’opérateur) peut être invoquée de 2 façons
// utilisation de la classe Vecteur void main() { Vecteur3d a(1,2,3), b(3,2,1), c, d; c = operator+(a, b); // notation fonctionnelle d = a + b; // notation usuelle for (int i=0; i<3; i++) cout << c.Get(i) << " " ; cout << endl; for (int i=0; i<3; i++) cout << d.Get(i) << " " ; }

9 Surcharge par une méthode
class Vecteur3d { public: Vecteur3d(int=0, int=0, int=0); int Get(int i); friend Vecteur3d operator+( const Vecteur3d&, const Vecteur3d&); int operator*(const Vecteur3d&) const; private: int x, y, z; }; Opérateur binaire: L’opérande gauche est l’instance courante L’opérande droite est le paramètre

10 // multiplication de 2 Vecteurs
int operator*(const Vecteur3d& v) const { int res; res = (this->x * v.x) + (y * v.y) + (z * v.z); return res; }

11 La méthode (l’opérateur) peut être invoquée de 2 façons
// utilisation de la classe Vecteur void main() { Vecteur3d a(1,2,3), b(3,2,1); int c, d; c = operator*(a, b); // notation fonctionnelle d = a * b; // notation usuelle cout << c << endl; cout << d << endl; }

12 Généralités De nombreux opérateurs peuvent être surchargés
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || >* , -> [] () new delete On doit conserver leur « pluralité » (unaire, binaire). Les opérateurs redéfinis gardent leur priorité et leur associativité (ordre d’évaluation) On ne doit pas faire d ’hypothèse sur la signification a priori d’un opérateur. Par exemple, la signification de += pour une classe ne peut en aucun cas être déduite de la signification de + et de = pour cette même classe.

13 Il n’est pas possible de définir de nouveaux opérateurs.
Un opérateur doit être soit une méthode d’une classe, soit une fonction prenant au moins un objet de classe en argument. En particulier, il n’est pas possible de définir une fonction opérateur ne prenant en argument que des pointeurs. Il n’est donc pas possible de modifier la signification des opérateurs usuels prédéfinis. Cela garantit que le C++ est extensible mais non-modifiable.

14 Cas particuliers Les opérateurs [], (), ->, new et delete doivent obligatoirement être définis par des méthodes (et non pas des fonctions) Les opérateurs = (affectation) et & (pointeur sur) possèdent une signification prédéfinie pour les objets de n’importe quel type classe mais peuvent être surchargés. Les opérateurs new et delete doivent obligatoirement avoir les prototypes suivants: class T { public: void * new(size_t); void delete(T*); . . . };

15 Opérateurs arithmétiques et relationnels
class Vecteur3d { public: Vecteur3d(int=0, int=0, int=0); int Get(int i); friend Vecteur3d operator+( const Vecteur3d&, const Vecteur3d&); int operator*(const Vecteur3d&) const; int operator==(const Vecteur3d& v) const; // comparaison Vecteur3d operator*(int) const; // produit friend Vecteur3d operator*(int, const Vecteur3d& v); private: int x, y, z; };

16 // comparaison int Vecteur3d::operator==(const Vecteur3d& v) const { return ((x == v.x) && (y == v.y) && (z == v.z)); } // produit vecteur-entier Vecteur3d Vecteur3d::operator*(int i) const { Vecteur3d v(x*i, y*i, z*i); return v; // produit entier-vecteur Vecteur3d operator*(int i, const Vecteur3d& v) { return v * i;

17 Opérateur d’affectation
Rappels importants Toute classe dispose, par défaut, d’un constructeur par copie et d’un opérateur d’affectation prédéfinis Ces opérateurs réalisent une copie champ à champ class Vecteur { public: Vecteur(int=10); ~Vecteur(); void Set(int i, int v); int Get(int i) const; private: int *tab; int nb; };

18 // recuperation dune valeur
int Vecteur::Get(int x) const { if ((x<0) || (x>=nb)) { cout << "erreur de rang" << endl; return 0; } return tab[x]; // constructeur Vecteur::Vecteur(int x) { tab = new int[x]; nb = x; } // affectation d’un element void Vecteur::Set(int x, int v){ if ((x<0) || (x>=nb)) { cout << "erreur de rang" << endl; x = 0; } tab[x] = v; // destructeur Vecteur::~Vecteur() { delete [] tab; }

19 Exemple de programme erroné:
void main() { Vecteur a(10), b(5); for (int i=0; i<10; i++) a.Set(i,i); b = a; Vecteur c(b); Vecteur d = b; } Opérateur d’affectation Constructeur par copie Destructeur pour a, b, c et d

20 Il faut surcharger le constructeur par copie
10 1 2 3 4 5 6 7 8 9 a ? b void main() { Vecteur a(10), b(5); for (int i=0; i<10; i++) a.Set(i,i); b = a; Vecteur c(b); Vecteur d = b; } 10 1 2 3 4 5 6 7 8 9 a ? b c d (détruit 4 fois) Constructions par copie et affectations sont sources d’erreurs Il faut surcharger le constructeur par copie et l’opérateur d’affectation

21 class Vecteur { public: Vecteur(int=10); Vecteur(const Vecteur&); // construction par copie ~Vecteur(); Vecteur& operator=(const Vecteur&); // affectation void Set(int x, int v); int Get(int x) const; private: int *tab; int nb; };

22 // construction par copie
Vecteur(const Vecteur& v) { tab = new int[v.nb]; for (int i=0; i<v.nb; i++) tab[i] = v.tab[i]; nb = v.nb; } // affectation Vecteur& operator=(const Vecteur& v) { if (this != &v) { delete [] tab; return *this;

23 Opérateurs d’entrée/sortie
On veut pouvoir utiliser les opérateurs << et >> pour afficher et saisir des vecteurs Leurs prototypes sont ostream& operator<<(ostream& os, const Vecteur& v); istream& operator>>(istream& os, Vecteur& v); ostream est le type de cout et istream celui de cin Ces opérateurs ne peuvent être définis comme étant des méthodes de la classe Vecteur. En effet, leur premier paramètre appartient à la classe ostream et istream. Il faudrait donc les définir comme étant méthodes de ces classes (ce qui est impossible). On doit donc les définir comme étant des fonctions amies de la classe Vecteur

24 class Vecteur { public: Vecteur(int=10); Vecteur(const Vecteur&); ~Vecteur(); Vecteur& operator=(const Vecteur&); void Set(int x, int v); int Get(int x) const; int operator==(const Vecteur& v) const; Vecteur operator*(int) const; friend Vecteur operator*(int, const Vecteur& v); friend ostream& operator<<(ostream&, const Vecteur&); friend istream& operator>>(istream&, Vecteur&); private: int *tab; int nb; };

25 // affichage friend ostream& operator<<(ostream& os, const Vecteur& v) { for (int i=0; i<v.nb; i++) os << v.tab[i] << endl; return os; } // saisie friend istream& operator>>(istream& is, Vecteur& v) is >> v.tab[i]; return is;

26 // test void main() { Vecteur a(10); cin >> a; // saisie Vecteur b(3); b = a; // affectation if (b==a) // comparaison cout << "c’est correct" << endl; else // affichage cout << "probleme" << endl << b << endl; }

27 Opérateur d’incrémentation et de décrémentation
Les opérateurs d ’incrémentation (++) et de décrémentation (--) peuvent être utilisés de manière préfixée (++x) ou postfixée (x++) Les opérateurs postfixés sont distingués des préfixés par l’emploi d ’un argument (de type int) supplémentaire non-utilisé class Vecteur { public: ... Vecteur operator++(); // prefixee Vecteur operator++(int); // postfixee private: };

28 // incrementation prefixee
Vecteur operator++() { for (int i=0; i<nb; i++) tab[i]++; return *this; } // incrementation postfixee Vecteur operator++(int) { Vecteur res = *this; ++(*this); return res;

29 Autres Opérateurs Beaucoup d’opérateurs peuvent être surchargés
A titre d’exemple, voici un opérateur d’indexation pour la classe Vecteur class Vecteur { public: ... int& operator[](int); private: };

30 Conclusion: le tableau tab est quasiment public (mais pas nb)
// adressage indexe int& operator[](int i) { if ((i < 0) || (i > nb)) { cout << "erreur de rang" << endl; i = 0; return tab[i]; } // Utilisation void main() { Vecteur a(5); for (int i=0; i<5; i++) a[i] = i; // ecriture for (int i=0; i<5; i++) cout << a[i] << endl; // lecture Conclusion: le tableau tab est quasiment public (mais pas nb)


Télécharger ppt "Les opérateurs L’amitié Les opérateurs Introduction"

Présentations similaires


Annonces Google