Contenu du cours
Programmation Orientée Objet en C++
Programmation Orientée Objet en C++
Surcharge des Opérateurs
La surcharge des opérateurs est une fonctionnalité puissante dans les langages de programmation orientée objet qui permet de redéfinir le comportement des opérateurs pour des classes
définies par l'utilisateur. En surchargeant les opérateurs, il est possible de fournir des implémentations personnalisées pour les opérations impliquant des objets de votre class
, ce qui permet d'écrire un code plus intuitif et expressif.
La syntaxe de la surcharge des opérateurs
La surcharge est réalisée en définissant des fonctions membres spéciales ou des fonctions amies qui implémentent le comportement souhaité pour l'opérateur. La syntaxe pour surcharger les opérateurs varie selon l'opérateur que vous souhaitez surcharger. La forme générale est la suivante :
overloading.h
return_type operator operator_symbol(parameters);
La syntaxe, ou plus précisément, le nombre de paramètres et le type de retour, dépend également du fait que vous surchargez les opérateurs en tant que fonctions membres ou fonctions amies.
Member.h
Friend.h
class Example { public: Example operator+ (const Example& other) { // Define behavior for operator+ } };
Tableau des opérateurs pouvant être surchargés
Voici un tableau répertoriant tous les opérateurs pouvant être surchargés. Cependant, il est important de noter que bien qu'il soit possible de surcharger ces opérateurs, il n'est en aucun cas nécessaire de tous les surcharger pour vos classes
.
Surcharge des opérateurs d'insertion de flux
Pour surcharger les opérateurs <<
et >>
pour une class
, il est courant de définir une fonction amie ou une fonction membre qui prend un flux de sortie (std::ostream&
) ou un flux d'entrée (std::istream&
) comme opérande gauche et un objet de votre class
comme opérande droit. Cette fonction formate ensuite les données de l'objet et les envoie vers ou depuis le flux.
Point.h
class Point { public: friend std::ostream& operator<<(std::ostream& out, const Point& point); friend std::istream& operator>>(std::istream& in, Point& point); private: int x, y; }; std::ostream& operator<<(std::ostream& out, const Point& point) { return out << "x: " << point.x << ", y: " << point.y << std::endl; } std::istream& operator>>(std::istream& in, Point& point) { return in >> point.x >> point.y; }
La surcharge des opérateurs d'insertion de flux, tels que <<
, permet de définir un comportement de sortie personnalisé pour les objets de vos classes
lorsqu'ils sont envoyés vers un flux de sortie comme std::cout
. Cette fonctionnalité est particulièrement utile pour améliorer la lisibilité et l'utilisabilité de votre code lors de la manipulation de types de données personnalisés.
La surcharge de l’opérateur <<
pour le flux de sortie est plus courante que la surcharge de l’opérateur >>
pour le flux d’entrée, car les opérations d’entrée avec >>
peuvent être plus sujettes aux erreurs.
Surcharge des opérateurs arithmétiques
Il est possible de surcharger d’autres opérateurs arithmétiques (-
, *
, /
, %
) de manière similaire afin d’effectuer des opérations personnalisées avec vos types définis par l’utilisateur.
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} Point operator+(const Point& other) { return Point(x + other.x, y + other.y); } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p = Point(2, 4) + Point(2, 6); std::cout << p.getX() << ' ' << p.getY() << std::endl; }
L'opérateur est surchargé en tant que fonction membre de la Point
class
. Il prend un autre objet Point
en paramètre et retourne un nouvel objet Point
représentant la somme des deux points. L'opérateur +
peut être remplacé par -
, *
, /
ou %
, avec les ajustements correspondants dans la logique d'implémentation.
Incrémentation et décrémentation
Les opérateurs d'incrémentation et de décrémentation, préfixés et postfixés (++
et --
) peuvent être surchargés pour des classes
personnalisées. Commençons par la version préfixée :
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Prefix increment operator (++point) Point& operator++() { ++x; ++y; return *this; } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); ++p; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
L'opérateur de décrémentation est surchargé de manière similaire à l'opérateur d'incrémentation, en utilisant l'opérateur --
et l'opération de soustraction.
Comme vous pouvez le constater, la surcharge des opérateurs d'incrémentation et de décrémentation préfixés est simple. Cependant, cela devient plus complexe avec les versions postfixées. N'oubliez pas qu'il existe une différence dans l'ordre d'exécution entre les opérations préfixées et postfixées.
Lors de la surcharge des opérateurs d'incrémentation et de décrémentation postfixés, il faut également implémenter la gestion de l'ordre d'exécution. Cela ressemblera à ceci :
main.cpp
#include <iostream> class Point { public: Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {} // Postfix increment operator (point++) Point operator++(int) { Point temp = *this; // Creating a temp variable ++(this->x); // Incrementing original Point's x ++(this->y); // Incrementing original Point's y return temp; // Returning created temp variable } int getX() { return x; } int getY() { return y; } private: int x, y; }; int main() { Point p(2, 2); p++; std::cout << p.getX() << ' ' << p.getY() << std::endl; }
Le paramètre entier est passé sans nom uniquement pour indiquer au compilateur que l'opérateur d'incrémentation postfixe est surchargé. Cela est nécessaire car les déclarations des opérateurs préfixe et postfixe sont autrement identiques.
Dans l'implémentation de l'opérateur d'incrémentation postfixe, la valeur d'origine de l'objet est stockée dans une variable temporaire (temp
). L'objet courant est ensuite incrémenté, mais l'opérateur retourne la valeur stockée dans temp
. Cela signifie que la variable est incrémentée, mais que la modification prend effet uniquement dans l'expression suivante, car l'opérateur retourne la valeur d'origine.
Merci pour vos commentaires !