| En C++, il est possible d'étendre le comportement des opérateurs pour qu'ils fonctionnent avec des classes personnalisées. Cette capacité permet d'attribuer des significations spécifiques aux opérateurs selon les types de données utilisés, ce que l'on appelle la surcharge d'opérateurs. |
|---|
En C++, nous pouvons rendre les opérateurs compatibles avec des classes définies par l'utilisateur. Cela signifie que le langage C++ permet d'associer des significations particulières aux opérateurs en fonction des types de données manipulés. Cette fonctionnalité est connue sous le nom de surcharge d'opérateurs.
Par exemple, nous pouvons surcharger l'opérateur '+' dans une classe de type Chaîne de caractères pour permettre la concaténation de deux chaînes simplement en utilisant le symbole '+'. D'autres classes où les opérateurs arithmétiques pourraient être surchargés incluent les nombres complexes, les décimaux, les grands entiers, etc.
Un exemple complet et simplifié
#include <iostream>
using namespace std;
class NombreComplexe {
private:
double reel, imaginaire;
public:
NombreComplexe(double r = 0, double i = 0) {
reel = r;
imaginaire = i;
}
NombreComplexe operator+(const NombreComplexe &obj) {
NombreComplexe resultat;
resultat.reel = reel + obj.reel;
resultat.imaginaire = imaginaire + obj.imaginaire;
return resultat;
}
void afficher() {
cout << reel << " + i" << imaginaire << endl;
}
};
int main()
{
NombreComplexe nc1(10.5, 5.2), nc2(2.3, 4.7);
NombreComplexe nc3 = nc1 + nc2;
nc3.afficher();
}
Quelle est la différence entre une fonction opérateur et une fonction ordinaire?
Une fonction opérateur fonctionne de la même manière qu'une fonction ordinaire. La seule différence réside dans le fait que le nom d'une fonction opérateur commence toujours par le mot-clé 'operator', suivi du symbole de l'opérateur correspondant. La fonction opérateur est appelée automatiquement lorsque l'opérateur correspondant est utilisé.
Voici un exemple de fonction opérateur globale.
#include <iostream>
using namespace std;
class NombreComplexe {
private:
double reel, imaginaire;
public:
NombreComplexe(double r = 0, double i = 0) {
reel = r;
imaginaire = i;
}
void afficher() {
cout << reel << " + i" << imaginaire << endl;
}
friend NombreComplexe operator+(const NombreComplexe &, const NombreComplexe &);
};
NombreComplexe operator+(const NombreComplexe &c1, const NombreComplexe &c2)
{
return NombreComplexe(c1.reel + c2.reel, c1.imaginaire + c2.imaginaire);
}
int main()
{
NombreComplexe nc1(10.5, 5.2), nc2(2.3, 4.7);
NombreComplexe nc3 = nc1 + nc2;
nc3.afficher();
return 0;
}
Peut-on surcharger tous les opérateurs?
Presque tous les opérateurs peuvent être surchargés, à quelques exceptions près. Voici la liste des opérateurs qui ne peuvent pas être surchargés :
Pourquoi les opérateurs . (point), ::, ? : et sizeof ne peuvent-ils pas être surchargés ?
Pour une réponse détaillée, se référer aux explications originales de Bjarne Stroustrup.
Points importants sur la surcharge d'opérateurs
- Pour que la surcharge d'opérateurs foncitonne, au moins un des opérandes doit être un objet de classe définie par l'utilisateur.
- Opérateur d'affectation : Le compilateur crée automatiquement un opérateur d'affectation par défaut pour chaque classe. Cet opérateur par affectation copie tous les membres de l'opérande droit vers l'opérande gauche et fonctionne dans la plupart des cas (ce comportement est similaire à celui du constructeur de copie).
- Opérateurs de conversion : Nous pouvons également écrire des opérateurs de conversion permettant de convertir un type en un autre.
#include <iostream>
using namespace std;
class Fraction
{
int numerateur, denominateur;
public:
Fraction(int n, int d) {
numerateur = n;
denominateur = d;
}
operator float() const {
return float(numerateur) / float(denominateur);
}
};
int main() {
Fraction f(2, 5);
float valeur = f;
cout << valeur;
return 0;
}
Les opérateurs de conversion surchargés doivent être des méthodes membres. Les autres opérateurs peuvent être des méthodes membres ou des fonctions globales.
- Tout constructeur pouvant être appelé avec un seul paramètre peut servir de constructeur de conversion, ce qui signifie qu'il peut également être utilisé pour une conversion implicite vers la classe en cours de construction.
#include <iostream>
using namespace std;
class Point
{
private:
int coordX, coordY;
public:
Point(int i = 0, int j = 0) {
coordX = i;
coordY = j;
}
void afficher() {
cout << endl << " x = " << coordX << ", y = " << coordY;
}
};
int main() {
Point p(20, 20);
p.afficher();
p = 30;
p.afficher();
return 0;
}