'>

les class_deuxieme partie

Surcharge des opérateurs
C + + intègre la possibilité d'utiliser les opérateurs classiques pour effectuer des opérations avec des classes en plus avec des types fondamentaux. Par exemple:

1
 2


   

 int a, b, c; a = b + c;



Il s'agit évidemment d'un code valide en C + +, puisque les différentes variables de l'ajout ya tous les types fondamentaux. Néanmoins, il n'est pas si évident que nous pourrions effectuer une opération similaire à la suivante:

 1
 2
 3
 4
 5


   

 struct { string product; float price; } a, b, c; a = b + c;



En fait, cela va provoquer une erreur de compilation, car nous n'avons pas défini le comportement de notre classe doit avoir avec opérations d'addition. Cependant, grâce à la fonction C + + pour les opérateurs de surcharge, nous pouvons concevoir des classes capables d'effectuer des opérations en utilisant des opérateurs classiques. Voici une liste de tous les opérateurs qui peuvent être surchargés:

Opérateurs surchargeables

 + - * / = <> + = - = * = / = << >>
 << = >> === = <=> = + + -!% & ^!  |
 ~ & = ^ = | = && | |% = [] (), -> * -> Nouveau
 supprimer new [] delete []


Pour surcharger un opérateur afin de l'utiliser avec des classes nous déclarer des fonctions d'opérateurs, qui sont des fonctions régulières dont les noms sont la clé de l'opérateur, suivi par le signe de l'opérateur que nous voulons surcharge. Le format est le suivant:

Signe de l'opérateur de type (paramètres) {/ * ... * /}

Ici vous avez un exemple qui surcharge l'opérateur d'addition (+). Nous allons créer une classe pour stocker des vecteurs bidimensionnels et puis nous allons ajouter deux d'entre eux: a (3,1) et B (1,2). L'addition de deux vecteurs bidimensionnels est une opération aussi simple que d'ajouter les deux coordonnées x pour obtenir la coordonnée x entraînant et en ajoutant les deux y coordonne pour obtenir le y résultant. Dans ce cas, le résultat sera (3 +1,1 +2) = (4,3).

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32


   

 // vectors: overloading operators example #include <iostream> using namespace std; class CVector { public : int x,y; CVector () {}; CVector ( int , int ); CVector operator + (CVector); }; CVector::CVector ( int a, int b) { x = a; y = b; } CVector CVector:: operator + (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); } int main () { CVector a (3,1); CVector b (1,2); CVector c; c = a + b; cout << cx << "," << cy; return 0; }

   

  4,3



Il peut être un peu déroutant de voir autant de fois l'identifiant CVector. Mais, n'oubliez pas que certains d'entre eux se réfèrent au nom de la classe (type) CVector et quelques autres sont des fonctions avec ce nom (constructeurs doivent avoir le même nom que la classe). Ne pas confondre:

 1
 2


   

 CVector ( int , int ); // function name CVector (constructor) CVector operator + (CVector); // function returns a CVector



La fonction opérateur + de classe CVector est celui qui est en charge de la surcharge de l'opérateur d'addition (+). Cette fonction peut être appelée implicitement en utilisant l'opérateur, ou en utilisant explicitement le nom de la fonction:

 1
 2


   

 c = a + b; c = a. operator + (b);



Les deux expressions sont équivalentes.

Notez également que nous avons inclus le constructeur vide (sans paramètres) et nous l'avons défini avec un bloc vide:



   

 CVector () { };



Cela est nécessaire, car nous avons explicitement déclaré un autre constructeur:



   

 CVector ( int , int );



Et quand nous déclarons explicitement tout constructeur, avec un certain nombre de paramètres, le constructeur par défaut sans paramètres que le compilateur peut déclarer automatiquement n'est pas déclarée, donc nous avons besoin de déclarer nous-mêmes afin d'être en mesure de construire des objets de ce type sans paramètres . Sinon, la déclaration:



   

 CVector c;



inclus dans main () n'aurait pas été valable.

Quoi qu'il en soit, je dois vous avertir que un bloc vide est une mauvaise mise en œuvre pour un constructeur, car elle ne remplit pas les fonctionnalités minimales que l'on attend généralement d'un constructeur, qui est l'initialisation de toutes les variables membres de sa catégorie. Dans notre cas, ce constructeur laisse les variables x et y indéfini. Par conséquent, une définition plus judicieux aurait été quelque chose de semblable à ceci:



   

 CVector () { x=0; y=0; };



qui, afin de simplifier et de montrer que le point du code, je n'ai pas inclus dans l'exemple.

Ainsi que d'un groupe un constructeur par défaut et un constructeur de copie, même si elles ne sont pas déclarées, il comprend également une définition par défaut pour l'opérateur d'affectation (=) à la classe elle-même en tant que paramètre. Le comportement qui est défini par défaut est de copier tout le contenu des données membres de l'objet passé en argument (l'un sur le côté droit du panneau) à celui de la gauche:

 1
 2
 3


   

 CVector d (2,3); CVector e; e = d; // copy assignment operator



La fonction d'opérateur d'affectation de copie est la seule fonction de membre de l'opérateur mis en place par défaut. Bien sûr, vous pouvez redéfinir à toute autre fonctionnalité que vous souhaitez, comme par exemple, ne copier que certains membres du groupe ou réaliser des procédures d'initialisation supplémentaires.

La surcharge des opérateurs ne force pas son fonctionnement à supporter une relation au sens mathématique ou habituel de l'opérateur, mais il est recommandé. Par exemple, le code peut ne pas être très intuitive si vous utilisez l'opérateur + pour soustraire deux classes ou opérateur == pour remplir avec des zéros d'une classe, mais il est parfaitement possible de le faire.

Bien que le prototype d'une fonction opérateur + peut sembler évident, car il faut ce qui est sur ​​le côté droit de l'opérateur en tant que paramètre à la fonction de membre de l'opérateur de l'objet à sa gauche, les autres opérateurs ne peuvent pas être si évident. Ici vous avez une table avec un résumé sur la façon dont les différentes fonctions de l'opérateur doivent être déclarées (@ remplacer par l'opérateur dans chaque cas):

Expression     Opérateur     fonction de membre     Fonction globale
@ Une     + - * &! ~ + + -     A :: opérateur @ ()     @ opérateur (A),
a @     + + -     A :: opérateur @ (int)     opérateur @ (A, int)
a @ b     + - * /% ^ &! | <> == = <=> = << >> && | |,     A :: opérateur @ (B)     @ opérateur (A, B)
a @ b     = + = - = * = / =% = ^ = & = | = << = >> = []     A :: opérateur @ (B)     -
un (B, C ...)     ()     A :: operator () (B, C. ..)     -
a-> x     ->     A :: opérateur-> ()     -
Où a est un objet de classe A, B est un objet de classe B et C est un objet de classe C.

Vous pouvez le voir dans ce tableau qu'il ya deux façons de surcharge des opérateurs de classe: en fonction de membre et comme une fonction globale. Son utilisation est indistinct, néanmoins, je vous rappelle que les fonctions qui ne sont pas membres d'une classe ne peuvent pas accéder aux membres privés ou protégés de cette catégorie à moins que la fonction globale est son ami (amitié est expliqué plus loin).

Le mot clé de cette
Le mot-clé this représente un pointeur vers l'objet dont la fonction membre est en cours d'exécution. Il s'agit d'un pointeur vers l'objet lui-même.

Une de ses utilisations peuvent être de vérifier si un paramètre passé à une fonction de membre est l'objet lui-même. Par exemple,

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22


   

 // this #include <iostream> using namespace std; class CDummy { public : int isitme (CDummy& param); }; int CDummy::isitme (CDummy& param) { if (&param == this ) return true ; else return false ; } int main () { CDummy a; CDummy* b = &a; if ( b->isitme(a) ) cout << "yes, &a is b" ; return 0; }

   

  oui, et une est b



Il est également fréquemment utilisé dans l'opérateur = fonctions membres qui retournent des objets par référence (en évitant l'utilisation d'objets temporaires). Suite aux exemples du vecteur vu avant nous aurions pu écrire un opérateur = fonction similaire à celle-ci:

 1
 2
 3
 4
 5
 6


   

 CVector& CVector:: operator = ( const CVector& param) { x=param.x; y=param.y; return * this ; }



En fait, cette fonction est très similaire au code que le compilateur génère implicitement de cette classe si nous n'incluons pas un opérateur = de la fonction de membre pour copier des objets de cette classe.

Les membres statiques
Une classe peut contenir des membres statiques, soit des données ou des fonctions.

Les membres de données statiques d'une classe sont également connus comme les "variables de classe", parce qu'il ya une seule valeur unique pour tous les objets de la même classe. Leur contenu n'est pas différent d'un objet de cette classe à l'autre.

Par exemple, il peut être utilisé pour une variable à l'intérieur d'une classe qui peut contenir un compteur avec le nombre d'objets de cette classe qui sont actuellement affectés, comme dans l'exemple suivant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22


   

 // static members in classes #include <iostream> using namespace std; class CDummy { public : static int n; CDummy () { n++; }; ~CDummy () { n--; }; }; int CDummy::n=0; int main () { CDummy a; CDummy b[5]; CDummy * c = new CDummy; cout << an << endl; delete c; cout << CDummy::n << endl; return 0; }

   

  7
  6



En fait, les membres statiques ont les mêmes propriétés que les variables globales, mais ils jouissent portée de la classe. Pour cette raison, et pour éviter d'être déclaré à plusieurs reprises, nous ne pouvons que comprendre le prototype (sa déclaration) dans la déclaration de classe, mais pas sa définition (son initialisation). Pour initialiser un membre de données statiques, nous devons inclure une définition formelle en dehors de la classe, dans le cadre global, comme dans l'exemple précédent:



   

 int CDummy::n=0;



Parce qu'il est une valeur variable unique pour tous les objets de la même classe, il peut être considéré comme un membre d'un objet de cette classe ou même directement par le nom de la classe (évidemment ceci n'est valable que pour les membres statiques):

 1
 2


   

 cout << an; cout << CDummy::n;



Ces deux appels inclus dans l'exemple précédent font référence à la même variable: la variable n statique dans CDummy de classes partagées par tous les objets de cette classe.

Encore une fois, je vous rappelle que, en fait, il s'agit d'une variable globale. La seule différence est son nom et restrictions d'accès en dehors de sa classe.

Tout comme nous pouvons inclure des données statiques dans une classe, nous pouvons également inclure des fonctions statiques. Ils représentent le même: ce sont des fonctions globales qui sont appelés comme s'ils étaient des membres objet d'une classe donnée. Ils ne peuvent se référer à des données statiques, en aucun cas, aux non-membres statiques de la classe, ainsi que ils ne permettent pas l'utilisation du mot-clé this, car il fait référence à un pointeur d'objet et ces fonctions, en fait, ne sont pas membres de tous les membres objet, mais directement de la classe. 
Publié par Drupal Study