en C++, la surcharge d'opérateurs est un polymorphisme au moment de la compilation. Il s'agit de donner une signification particulière à un opérateur existant en C++ sans changer sa signification originale.
Dans cet article, nous discuterons plus en détail de la surcharge d'opérateurs en C++ avec des exemples et verrons quels opérateurs nous pouvons ou ne pouvons pas surcharger en C++.
Surcharge des opérateurs C++
C++ a la capacité de fournir aux opérateurs une signification particulière pour un type de données, cette capacité est connue sous le nom de surcharge d'opérateurs. La surcharge d'opérateurs est un polymorphisme au moment de la compilation. Par exemple, nous pouvons surcharger un opérateur « + » dans une classe comme String afin de pouvoir concaténer deux chaînes en utilisant simplement +. D'autres exemples de classes où les opérateurs arithmétiques peuvent être surchargés sont les nombres complexes, les nombres fractionnaires, les grands entiers, etc.
Exemple:
int a; float b,sum; sum = a + b;>
Ici, les variables a et b sont de types int et float, qui sont des types de données intégrés. Par conséquent, l’opérateur d’addition « + » peut facilement ajouter le contenu de a et b. En effet, l'opérateur d'addition + est prédéfini pour ajouter uniquement des variables de type de données intégré.
Mise en œuvre:
C++
// C++ Program to Demonstrate the> // working/Logic behind Operator> // Overloading> class> A {> >statements;> };> int> main()> {> >A a1, a2, a3;> >a3 = a1 + a2;> >return> 0;> }> |
int analyseur
>
>
Dans cet exemple, nous avons 3 variables a1, a2 et a3 de type classe A. Ici, nous essayons d'ajouter deux objets a1 et a2, qui sont de type défini par l'utilisateur, c'est-à-dire de type classe A en utilisant l'opérateur +. Ceci n'est pas autorisé, car l'opérateur d'addition + est prédéfini pour fonctionner uniquement sur les types de données intégrés. Mais ici, la classe A est un type défini par l'utilisateur, donc le compilateur génère une erreur. C'est là qu'intervient le concept de surcharge de l'opérateur.
Désormais, si l'utilisateur souhaite que l'opérateur + ajoute deux objets de classe, l'utilisateur doit redéfinir la signification de l'opérateur + de telle sorte qu'il ajoute deux objets de classe. Cela se fait en utilisant le concept de surcharge d'opérateur. L'idée principale derrière la surcharge d'opérateurs est donc d'utiliser des opérateurs C++ avec des variables de classe ou des objets de classe. Redéfinir le sens des opérateurs ne change vraiment pas leur sens originel ; au lieu de cela, ils ont reçu une signification supplémentaire en plus de celle existante.
Exemple de surcharge d'opérateur en C++
C++
// C++ Program to Demonstrate> // Operator Overloading> #include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >// This is automatically called when '+' is used with> >// between two Complex objects> >Complex operator+(Complex>const>& obj)> >{> >Complex res;> >res.real = real + obj.real;> >res.imag = imag + obj.imag;> >return> res;> >}> >void> print() { cout << real <<>' + i'> << imag <<>'
'>; }> };> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3 = c1 + c2;> >c3.print();> }> |
>
>Sortir
12 + i9>
Différence entre les fonctions de l'opérateur et les fonctions normales
Les fonctions de l'opérateur sont les mêmes que les fonctions normales. Les seules différences sont que le nom d'une fonction opérateur est toujours le mot-clé de l'opérateur suivi du symbole de l'opérateur, et les fonctions de l'opérateur sont appelées lorsque l'opérateur correspondant est utilisé.
Exemple
C++
#include> using> namespace> std;> class> Complex {> private>:> >int> real, imag;> public>:> >Complex(>int> r = 0,>int> i = 0)> >{> >real = r;> >imag = i;> >}> >void> print() { cout << real <<>' + i'> << imag << endl; }> >// The global operator function is made friend of this> >// class so that it can access private members> >friend> Complex operator+(Complex>const>& c1,> >Complex>const>& c2);> };> Complex operator+(Complex>const>& c1, Complex>const>& c2)> {> >return> Complex(c1.real + c2.real, c1.imag + c2.imag);> }> int> main()> {> >Complex c1(10, 5), c2(2, 4);> >Complex c3> >= c1> >+ c2;>// An example call to 'operator+'> >c3.print();> >return> 0;> }> |
>
>
motif d'étoile impriméSortir
12 + i9>
Pouvons-nous surcharger tous les opérateurs ?
Presque tous les opérateurs peuvent être surchargés, sauf quelques-uns. Voici la liste des opérateurs qui ne peuvent pas être surchargés.
sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)>
Opérateurs pouvant être surchargés en C++
Nous pouvons surcharger
Opérateurs unaires Opérateurs binaires Opérateurs spéciaux ( [ ], (), etc.)
Mais parmi eux, certains opérateurs ne peuvent pas être surchargés. Ils sont
Opérateur de résolution de périmètre ( : Opérateur de sélection de membres Sélection de membres via *
Pointeur vers une variable membre
- Opérateur conditionnel (? Opérateur Sizeof sizeof()
| Opérateurs pouvant être surchargés | Exemples |
|---|---|
| Arithmétique binaire | +, -, *, /, % |
| Arithmétique unaire | +, -, ++, — |
| Affectation | =, +=,*=, /=,-=, %= |
| Au niveau du bit | &, | , <> , ~ , ^ |
| Déréférencement | (->) |
| Allocation dynamique de mémoire, Désallocation | Nouveau, supprimer |
| Indice | [ ] |
| Appel de fonction | () |
| Logique | &, | |, ! |
| Relationnel | >, <, = =, = |
Pourquoi les opérateurs mentionnés ci-dessus ne peuvent-ils pas être surchargés ?
1. taille de l'opérateur
Cela renvoie la taille de l'objet ou du type de données saisi comme opérande. Ceci est évalué par le compilateur et ne peut pas être évalué pendant l'exécution. L’incrémentation appropriée d’un pointeur dans un tableau d’objets repose implicitement sur l’opérateur sizeof. Modifier sa signification en utilisant une surcharge entraînerait l’effondrement d’une partie fondamentale du langage.
2. Opérateur typeid
Cela fournit à un programme CPP la capacité de récupérer le type réellement dérivé de l'objet référencé par un pointeur ou une référence. Pour cet opérateur, le tout est d’identifier un type de manière unique. Si nous voulons qu'un type défini par l'utilisateur « ressemble » à un autre type, le polymorphisme peut être utilisé mais la signification de l'opérateur typeid doit rester inchangée, sinon de sérieux problèmes pourraient survenir.
3. Résolution de la portée (::) Opérateur
Cela permet d'identifier et de spécifier le contexte auquel un identifiant fait référence en spécifiant un espace de noms. Il est entièrement évalué au moment de l'exécution et fonctionne sur les noms plutôt que sur les valeurs. Les opérandes de résolution de portée sont des expressions de notes avec des types de données et CPP n'a pas de syntaxe pour les capturer s'il était surchargé. Il est donc syntaxiquement impossible de surcharger cet opérateur.
4. Opérateurs d'accès aux membres du groupe (.(point ), .* (pointeur vers l'opérateur membre))
L'importance et l'utilisation implicite des opérateurs d'accès aux membres de classe peuvent être comprises à travers l'exemple suivant :
Exemple:
C++
// C++ program to demonstrate operator overloading> // using dot operator> #include> using> namespace> std;> class> ComplexNumber {> private>:> >int> real;> >int> imaginary;> public>:> >ComplexNumber(>int> real,>int> imaginary)> >{> >this>->réel = réel ;> >this>->imaginaire = imaginaire;> >}> >void> print() { cout << real <<>' + i'> << imaginary; }> >ComplexNumber operator+(ComplexNumber c2)> >{> >ComplexNumber c3(0, 0);> >c3.real =>this>->réel + c2.real;> >c3.imaginary =>this>->imaginaire + c2.imaginaire;> >return> c3;> >}> };> int> main()> {> >ComplexNumber c1(3, 5);> >ComplexNumber c2(2, 4);> >ComplexNumber c3 = c1 + c2;> >c3.print();> >return> 0;> }> |
>
>Sortir
5 + i9>
Explication:
L'instruction ComplexNumber c3 = c1 + c2; est traduit en interne par ComplexNumber c3 = c1.operator+ (c2); afin d'invoquer la fonction opérateur. L'argument c1 est implicitement passé en utilisant le '.' opérateur. L'instruction suivante utilise également l'opérateur point pour accéder à la fonction membre print et transmettre c3 comme argument.
En outre, ces opérateurs fonctionnent également sur des noms et non sur des valeurs et il n'est pas prévu (syntaxiquement) de les surcharger.
5. Opérateur ternaire ou conditionnel (?:)
L'opérateur ternaire ou conditionnel est une représentation abrégée d'une instruction if-else. Dans l'opérateur, les expressions vrai/faux sont évaluées uniquement sur la base de la valeur de vérité de l'expression conditionnelle.
conditional statement ? expression1 (if statement is TRUE) : expression2 (else)>
Une fonction surchargeant l'opérateur ternaire pour une classe, par exemple ABC, en utilisant la définition
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);>
ne serait pas en mesure de garantir qu’une seule des expressions soit évaluée. Ainsi, l’opérateur ternaire ne peut pas être surchargé.
Points importants concernant la surcharge des opérateurs
1) Pour que la surcharge d'opérateurs fonctionne, au moins un des opérandes doit être un objet de classe défini par l'utilisateur.
hachage dans la structure de données
2) Opérateur d'affectation : Le compilateur crée automatiquement un opérateur d'affectation par défaut avec chaque classe. L'opérateur d'affectation par défaut attribue tous les membres du côté droit au côté gauche et fonctionne correctement dans la plupart des cas (ce comportement est le même que celui du constructeur de copie). Voir ceci pour plus de détails.
3) Opérateur de conversion : Nous pouvons également écrire des opérateurs de conversion qui peuvent être utilisés pour convertir un type en un autre type.
Exemple:
C++
javascript
// C++ Program to Demonstrate the working> // of conversion operator> #include> using> namespace> std;> class> Fraction {> private>:> >int> num, den;> public>:> >Fraction(>int> n,>int> d)> >{> >num = n;> >den = d;> >}> >// Conversion operator: return float value of fraction> >operator>float>()>const> >{> >return> float>(num) />float>(den);> >}> };> int> main()> {> >Fraction f(2, 5);> >float> val = f;> >cout << val <<>'
'>;> >return> 0;> }> |
>
>Sortir
0.4>
Les opérateurs de conversion surchargés doivent être une méthode membre. D'autres opérateurs peuvent être la méthode membre ou la méthode globale.
4) Tout constructeur pouvant être appelé avec un seul argument fonctionne comme un constructeur de conversion, ce qui signifie qu'il peut également être utilisé pour une conversion implicite vers la classe en cours de construction.
Exemple:
C++
// C++ program to demonstrate can also be used for implicit> // conversion to the class being constructed> #include> using> namespace> std;> class> Point {> private>:> >int> x, y;> public>:> >Point(>int> i = 0,>int> j = 0)> >{> >x = i;> >y = j;> >}> >void> print()> >{> >cout <<>'x = '> << x <<>', y = '> << y <<>'
'>;> >}> };> int> main()> {> >Point t(20, 20);> >t.print();> >t = 30;>// Member x of t becomes 30> >t.print();> >return> 0;> }> |
>
>Sortir
x = 20, y = 20 x = 30, y = 0>
Quiz sur la surcharge des opérateurs