Les opérateurs en haut de la liste sont évalués en premiers. Les opérateurs à l'intérieur d'un même groupe partagent la même précédence. Tout les opérateurs ont une associativité de gauche à droite sauf exception.
Opérateur | Description | Exemple | Surchargeable |
---|---|---|---|
Groupe 1 (pas d'associativité) |
|||
:: | Opérateur de résolution | Class::age = 2; | NON |
Groupe 2 | |||
() | Appel de fonction | isdigit('1') | OUI |
() | Initialisation de membre | c_tor(int x, int y) : _x(x), _y(y*10){}; | OUI |
[] | Accès à l'élément d'un tableau | array[4] = 2; | OUI |
-> | Accès à un membre depuis un pointeur | ptr->age = 34; | OUI |
. | Accès à un membre depuis un objet | obj.age = 34; | NON |
++ | Post-incrémentation | for( int i = 0; i < 10; i++ ) cout << i; | OUI |
-- | Post-décrémentation | for( int i = 10; i > 0; i-- ) cout << i; | OUI |
const_cast | Transtypage | const_cast<type_vers>(type_de); | NON |
dynamic_cast | Transtypage | dynamic_cast<type_vers>(type_de); | NON |
static_cast | Transtypage | static_cast<type_vers>(type_de); | NON |
reinterpret_cast | Transtypage | reinterpret_cast<type_vers>(type_de); | NON |
typeid | Information sur le type | cout << typeid(var).name(); cout << typeid(type).name(); | NON |
Groupe 3 (associativité droite-à-gauche) |
|||
! | Négation logique | if( !fini ) … | OUI |
not | Autre notation pour ! | ||
~ | Complément bit à bit | drapeaux = ~drapeaux; | OUI |
compl | Autre notation pour ~ | ||
++ | Pré-incrémentation | for( i = 0; i < 10; ++i ) cout << i; | OUI |
-- | Pré-décrémentation | for( i = 10; i > 0; --i ) cout << i; | OUI |
- | Moins unaire | int i = -1; | OUI |
+ | Plus unaire | int i = +1; | OUI |
* | Déréferenciation | int data = *intPtr; | OUI |
& | Adresse de | int *intPtr = &data; | OUI |
new | Allocation dynamique de mémoire | long *pVar = new long; MyClass *ptr = new MyClass(args); | OUI |
new [] | Allocation dynamique de mémoire pour tableau | long *array = new long[n]; | OUI |
delete | Désallocation de mémoire | delete pVar; | OUI |
delete [] | Désallocation de mémoire d'un tableau | delete [] array; | OUI |
(type) | Transtypage vers un type donné | int i = (int) floatNum; | OUI |
sizeof | Taille d'un objet ou d'un type | int size = sizeof floatNum; int size = sizeof(float); | NON |
Groupe 4 | |||
->* | Accès à un membre pointé depuis un pointeur | ptr->*var = 24; | OUI |
.* | Accès à un membre pointé | obj.*var = 24; | NON |
Groupe 5 | |||
* | Multiplication | int i = 2 * 4; | OUI |
/ | Division | float f = 10.0 / 3.0; | OUI |
% | Modulo | int rem = 4 % 3; | OUI |
Groupe 6 | |||
+ | Addition | int i = 2 + 3; | OUI |
- | Soustraction | int i = 5 - 1; | OUI |
Groupe 7 | |||
<< | Décalage binaire à gauche | int drapeaux = 33 << 1; | OUI |
>> | Décalage binaire à droite | int drapeaux = 33 >> 1; | OUI |
Groupe 8 | |||
< | Comparaison inférieur à | if( i < 42 ) … | OUI |
<= | Comparaison inférieur ou égal à | if( i <= 42 ) ... | OUI |
> | Comparaison supérieur à | if( i > 42 ) … | OUI |
>= | Comparaison supérieur ou égal à | if( i >= 42 ) ... | OUI |
Groupe 9 | |||
== | Comparaison égal à | if( i == 42 ) ... | OUI |
eq | Autre notation pour == | ||
!= | Comparaison non égal à | if( i != 42 ) … | OUI |
not_eq | Autre notation pour != | ||
Groupe 10 | |||
& | ET bit à bit | drapeaux = drapeaux & 42; | OUI |
bitand | Autre notation pour & | ||
Groupe 11 | |||
^ | OU exclusif bit à bit (XOR) | drapeaux = drapeaux ^ 42; | OUI |
xor | Autre notation pour ^ | ||
Groupe 12 | |||
| | OU inclusif bit à bit (normal) | drapeaux = drapeaux | 42; | OUI |
bitor | Autre notation pour | | ||
Groupe 13 | |||
&& | ET logique | if( conditionA && conditionB ) … | OUI |
and | Autre notation pour && | ||
Groupe 14 | |||
|| | OU logique | if( conditionA || conditionB ) ... | OUI |
or | Autre notation pour || | ||
Groupe 15 (associativité droite-à-gauche) |
|||
? : | Condition ternaire (si-alors-sinon) | int i = (a > b) ? a : b; | NON |
Groupe 16 (associativité droite-à-gauche) |
|||
= | Opérateur d'assignement | int a = b; | OUI |
+= | Incrémenter et assigner | a += 3; | OUI |
-= | Décrémenter et assigner | b -= 4; | OUI |
*= | Multiplier et assigner | a *= 5; | OUI |
/= | Diviser et assigner | a /= 2; | OUI |
%= | Modulo et assigner | a %= 3; | OUI |
&= | ET bit à bit et assigner | drapeaux &= nouveaux_drapeaux; | OUI |
and_eq | Autre notation pour &= | ||
^= | OU exclusif bit à bit (XOR) et assigner | drapeaux ^= nouveaux_drapeaux; | OUI |
xor_eq | Autre notation pour ^= | ||
|= | OU normal bit à bit et assigner | drapeaux |= nouveaux_drapeaux; | OUI |
or_eq | Autre notation pour |= | ||
<<= | Décalage binaire à gauche et assigner | drapeaux <<= 2; | OUI |
>>= | Décalage binaire à droite et assigner | drapeaux >>= 2; | OUI |
Groupe 17 | |||
throw | Lever une exception | throw EClass(“Message”); | NON |
Groupe 18 | |||
, | Opérateur d'évaluation séquentielle | for( i = 0, j = 0; i < 10; i++, j++ ) … | OUI |
L'un des aspects importants du C++ qui est relié à la précédence des opérateurs est l'ordre d'évaluation et l'ordre des effets de bords dans les expressions. Dans certaines circonstances, l'ordre dans lequel les choses se passent n'est pas défini. Par exemple, étudions le code suivant:
float x = 1; x = x / ++x;
Il n'est pas garanti que la valeur de x soit constante selon différent compilateurs, parce qu'il n'est pas clairement spécifié si l'ordinateur doit évaluer le coté gauche ou droit de la division en premier. Selon le coté évalué en premier, x peut prendre une valeur différente.
De plus, alors que ++x est évalué comme x+1, le fait de stocker la nouvelle valeur dans x peut se passer à différents moments, résultant de différentes valeurs pour x.
Enfin, les expressions comme celle-ci sont horriblement ambiguës et doivent à tout prix être évitées. Dans le doute, séparez une expression ambiguë en plusieurs expressions pour assurer que l'ordre d'évaluation est correct.
La surcharges des opérateurs peut être très utile et très dangereuse. D'un coté surcharger les opérateurs d'une classe que vous avez crée peut simplifier le code et améliorer sa lisibilité. D'un autre coté vous pouvez surcharger un opérateur d'une telle façon que cela peut masquer un problème ou simplement boguer votre programme. A utiliser avec précaution.
Il y a deux façon de surcharger un opérateur: par une fonction globale ou un membre de classe.
Exemple de surcharge par une fonction global:
ostream & operator<< (ostream & os, const maClasse & rhs);
Mais pour être capable d'atteindre toutes les données privées définies dans une classe vous devez déclarer la fonction globale comme amie dans la definition de la classe.
Exemple:
class maClasse { // Donne à la fonction operator<< accès à 'maDonnee' // (cette déclaration ne doit pas être définie comme publique, privée ou protégée) friend ostream & operator<< (ostream & lhs, const maClasse & rhs); private: int maDonnee; }
La surcharge par un membre de classe peut être faite comme cela:
class maClasse { public: // Le coté gauche de l'opérateur est un pointeur vers 'this'. int operator+ (const maClasse & rhs); private: int maDonnee; }