Previous Next Contents




Classes-III : sommaire


Classes-III  1


Surcharge des Opérateurs

+ - * / % ^ & |
~ ! , = < > <= >=
++ - - << >> == != && ||
+= -= /= *= %= ^= &= |=
<<= >>= [] () -> ->* new delete


Classes-III  2


Surcharge des Opérateurs (2)


Classes-III  3




Relation entre une opération et l'appel de fonction associé

expression fonction membre fonction non
    membre
++a a.operator++() operator++(a)
a+b a.operator+(b) operator+(a,b)
a=b a.operator=(b) impossible
a() a.operator()() impossible
a[b] a.operator[](b) impossible
a-> a.operator->() impossible
a++ a.operator++(1) operator++(a,1)


Les opérateurs postfixés sont distingués des opérateurs préfixés par un second argument ``bidon'' de type int
T operator++() // opérateur préfixé
T operator++(int) // opérateur postfixé


Classes-III  4


Opérateur d'affectation

class String {
   int len ; char * pt ;
public:
   String(const char *ch) {
    len = strlen(ch);
    pt=new char[len+1];
    strcpy(pt,ch);
   }
   ~String() { delete [] pt; }
} ;
String s1("toto");
String s2("foo");
s2 = s1; // recopie membre à membre
// s2.pt est écrasé par s1.pt
// Þ espace pointé par s2.pt perdu
s1.set("coucou");
// Þ chaîne de s2 modifiée en même temps
// s2.len==4 et s2.pt=="coucou"
Problème lors de l'exécution !!!


Classes-III  5


... Solution : surcharger l'opérateur =
class String {
   int len ; char * pt ;
public:
   String(const char *ch) {
    len = strlen(ch);
    pt=new char[len+1];
    strcpy(pt,ch);
   }
   ~String() { delete [] pt; }
   String& operator=(String&);
   ...
};
// Noter le retour d'une référence
String& String::operator=(String& s) {
   if (this != &s) {
    // protection vis a vis de x=x
    delete [] pt ; // libération mémoire
    len = s.len;
    pt = new char[len+1];
    pt = strcpy(s.pt) ;
   }
   return *this;
}


Classes-III  6


Opérateur d'indexation

Déclaration :
class TabInt {
   int *data, taille;
public :
   TabInt(int dim) : taille(dim) {
    data = new int[dim]; }
   int& operator[](int);
};

Définition :
int& TabInt::operator[](int ind) {
   if ((ind<0) || (ind >= taille)) {
    cout << "Erreur de borne" << endl;
    exit(1);
   }
   return data[ind];
}

Utilisation :
TabInt tab = TabInt(10);
for (int i=0; i<10; i++)
   tab[i] = i ;


Classes-III  7


Opérateurs +=, -=, *=, ...

Déclaration :

class Point {
   int x,y; ...
public :
   Point(int a, int b) : x(a), y(b) {}
   Point(int a=0) : x(a), y(a) {}
   Point& operator+=(const Point&);
   ...
};

Définition :
Point& Point::operator+=(const Point& p) {
   x+=p.x; y+=p.y;
   return *this;
}

Utilisation :
Point p1(2,3), p2(1,2) ;
p1 += p2 ;
p1 += 1; // OK : p1 += Point(1)


Classes-III  8


Opérateurs +, -, *, ...

class Complex {
   double r,i; ...
public :
   Complex(double = 0.0, double = 0.0);
   Complex operator+(const Complex&) ;
};

Complex Complex::operator+(const Complex& p2)
{ return Complex(r+p2.r, i+p2.i) ; }

int main(void) {
   Complex a(1.0), b(2.,3.);
   Complex c = a + b ; // OK
   Complex d = b + 1.0;//OK: b+Complex(1.)
   Complex e = 1.0 + c; // Erreur compil.
}
Problème de compilation !!!


Classes-III  9


...Solution : définir opérateur + comme non-membre

Déclaration :
class Complex { // ...
public :
   Complex(double = 0.0, double = 0.0);
   friend Complex operator+(const Complex&,
    const Complex&) ;
};

Définition :
Complex operator+(const Complex& p1,
    const Complex& p2) {
   return Complex(p1.r+p2.r, p1.i+p2.i) ;
}

Utilisation :
int main(void) {
   Complex c(1.0);
   Complex d = c + 1.0; // OK
   Complex e = 1.0 + c; // OK
}


Classes-III  10




Les temporaires

compteur operator+(const compteur& c1,
    const compteur& c2) {
   return compteur(c1.valeur+c2.valeur) ;
}
...
compteur a,b,c;
...
a = b+c+4;
// temp1 = b+c
// temp2 = compteur(4)
// temp3 = temp1+temp2
// a = temp3


Classes-III  11


Opérateurs d'entrées/sorties

Pour surcharger les opérations sur les flots d'entrées/sorties afin de les appliquer aux nouveaux types définis.

Déclaration :
class Point {
   friend ostream& operator<<( ostream&,
    const Point&);
   ...
};

Définition :
ostream& operator<<(ostream& stream,
   const Point& p) {
   return stream << p.x << " " << p.y;
}

Utilisation :
Point p(2,3);
cout << "p = " << p << endl ;


Classes-III  12


Opérateur de conversion de type

class Rationnel {
   int num,den;
public :
   Rationnel(int n=0, int d=1) : num(n),
    den(d) {}
// op. de conversion vers double
   operator double() const {
    return ((double)num)/den);
   }
};

Utilisation :

Rationnel r = Rationnel(4) ;
x = sqrt(double(Rationnel(2,3)));


Classes-III  13


Opérateurs de gestion mémoire

Exemple :
#include <stddef.h>
class Point {
private :
   int x,y;
   Point *next;
   static Point *freeP;
   static const int packNb;
public :
   ...
   void* operator new(size_t);
   void operator delete(void *);
};
void* Point::operator new(size_t sz) {
   Point *p;
   if (!freeP) {
    size_t packSz = packNb*sz;
    // Alloc. espace pr packNb Points
    freeP = (Point *)new char[packSz];
    for (int i=1,p=freeP;i<packNb;i++,p++)
    p->next = p+1;// Mise en liste
    p->next = 0;
   }
   p=freeP; freeP=freeP->next;
   return p;
}
void Point::operator delete(void* pt) {
   ((Point*)pt)->next = freeP;
   freeP = (Point*)pt;
}
Point* Point::freeP=0;
const int packNb=50;
Point* p = new Point(3,4);
// Point::new(sizeof(Point))
//   puis Point::Point(3,4)


Classes-III  14


Implémentation usuelle des opérateurs






Opérateur Réalisation Retour
[] DOIT être membre réf. à qqch
(), ->, ->*, * DOIT être membre selon cas
++, - - membre réf. à l'objet
conversion DOIT être membre selon cas
!, ~, ... (unaires) membre selon cas
= DOIT être membre réf. à l'objet
+=, /=, ... membre réf. à l'objet
+, -, /, ... non-membre nouvel objet
<<, >> (I/O) DOIT être non-membre réf. à stream
new DOIT être membre void*
delete DOIT être membre void




Previous Next Contents