Compilation & Directives de préprocesseur Pointeurs, Références & Allocation Dynamique de Mémoire Spécificités du C++ (indépendantes de la POO) Structures & Classes Encapsulation des données Constructeur & Destructeur de classe Copie d'objets Amitié & Surcharge d'opérateur Héritage (Partie 1) Héritage (Partie 2) Patrons de fonctions et de classes Introduction à la librairie standard
Retour menu principal

Surcharge d’opérateur


Surcharge d’opérateur

  • C++ permet de surdéfinir les opérateurs tels que +, =, +=, ++, <<, new
  • Fondamentalement, l’appel à un opérateur est identique à l’appel d’une fonction → possibilité de surdéfinir
  • Le but est de définir ces “fonctions” pour des classes dépourvues de ces opérateurs

Exemple de surcharge de l’opérateur unaire +=

Objectif : réaliser ce type d’opération logique

int main()
{
  point my_point1(2, 3);
  point my_point2(4, 5);
  my_point1 += my_point2;
}

Exemple de surcharge de l’opérateur unaire +=

// Déclaration
class point
{
public:
  point();
  point(const double x_, const double y_);
  double x() const;
  double y() const;


private:
  double m_x;
  double m_y;
};

Exemple de surcharge de l’opérateur unaire +=

// Déclaration
class point
{
public:
  point();
  point(const double x_, const double y_);
  double x() const;
  double y() const;
  point & operator+=(const point & point_);

private:
  double m_x;
  double m_y;
};

Exemple de surcharge de l’opérateur unaire +=

// Définition
point & point::operator+=(const point & point_)
{
  m_x += point_.x();
  m_y += point_.y();
  return *this;
}

→ utilisation du pointeur this qui retourne l'adresse de l'objet courant

Exemple de surcharge de l’opérateur unaire +=

// Définition
point & point::operator+=(const point & point_)
{
  m_x += point_.x();
  m_y += point_.y();
  return *this;
}
...
// Utilisation
int main()
{
  point my_point1(2, 3);
  point my_point2(4, 5);
  my_point1 += my_point2;
}

→ équivalent à l'usage d'une méthode ajoute s'utilisant de la façon suivante my_point1.ajoute(my_point2);

Exemple de surcharge de l’opérateur binaire +

int main()
{
  point my_point1(2, 3);
  point my_point2(4, 5);
  point my_point3 = my_point1 + my_point2;
}
// Déclaration
class point
{
  ...
};
point operator+(const point & point1_, const point & point2_);

// Définition
point operator+(const point & point1_, const point & point2_)
{
  return point(point1_.x() + point2_.x(), point1_.y() + point2_.y());
}

Opérateur d’affectation =

  • L’opérateur d’affectation = permet d’affecter une nouvelle valeur à un objet déjà existant

    int main()
    {
      point my_point1(2, 3);
      point my_point2(3, 4);
      my_point2 = my_point1;
    }
    
  • Sa surcharge se fait comme pour n’importe quel opérateur

    // Déclaration
    class point
    {
      point & operator=(const point & point_);
    };
    

Opérateur d’affectation =

  • Rien n’empêche toutefois d’affecter un objet à lui-même

    point my_point;
    my_point = my_point;
    
  • Lorsque cette “affectation” risque de corrompre l’objet, utiliser un garde-fou :

    // Définition
    point & point::operator=(const point & point_)
    {
      if (&point_ != this) { // garde-fou
        m_x = point_.x();
        m_y = point_.y();
      }
      return *this;
    }
    

Constructeur de recopie et opérateur d’affectation =

  • Le constructeur de recopie est la méthode appelée lors de la copie d’un objet vers un autre objet du même type

    int main()
    {
      point my_point1(2, 3);
      point my_point2 = my_point1;
    }
    
    class point
    {
      point(const point & point_);
    };
    
    point::point(const point & point_)
    {
      m_x = point_.x();
      m_y = point_.y();
    }
    

Constructeur de recopie et opérateur d’affectation =

  • C++ fournit par défaut le constructeur de recopie et l’opérateur d’affectation =
  • Lorsque ces versions triviales ne suffisent pas (cas de l'allocation dynamique) il faut choisir entre deux solutions :
    • Écrire une version correcte,
    • Rendre impossible la copie et l’affectation, en déclarant ces méthodes privées, sans les définir :

      class pas_de_copie
      {
      private:
        pas_de_copie(const pas_de_copie&);
        pas_de_copie & operator=(const pas_de_copie&);
      };
      

Annexes

Fonctions et classes amies

  • Du fait du principe d’encapsulation des données, les fonctions extérieures à la classe n’ont pas accès aux membres privées de cette classe…
  • … à l’exception des fonctions amies
  • Utilité : quasi nulle sauf pour quelques opérations (dont la surcharge d’opérateur)

Exemple de fonction amie d’une classe

// Déclaration avec friend
class particule
{
  friend void stupid_thing(particule & particule_);
  ...
};
...
// Définition
void stupid_thing(particule & particule_)
{
  particule_.m_mass = 0.511;
}
...
// Utilisation
int main()
{
  particule my_muon(105.6, -1.6e-19);
  stupid_thing(my_muon);
  // muon $\equiv$ électron ?? wtf !!
}

Classe amie d’une autre classe

  • Méthode d’une classe B, amie d’une autre classe A

    class A
    {
      ...
      friend void B::methode_de_B(A & A_);
      ...
    };
    
  • Classe B amie d’une autre classe A

    class A
    {
      ...
      friend class B;
      ...
    };