Les classes et les objets Cours 2 Les classes et les objets (suite) INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Plan du cours 2 Objets et membres constants Pointeur this Surcharge d’opérateurs Membres statiques INF1101 Algorithmes et structures de données
I. Objets et membres constants Mot clé const Mot clé du langage spécifiant qu’aucune modification d’un objet, d’une variable ou d’un pointeur n’est permise. La signification du const dans la signature d’une fonction membre d’une classe dépend de sa position. INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données const (suite) Attribut: la valeur est constante, fixée à la création de l’objet. Fonction membre const : ne modifie pas l’objet courant, peut seulement accéder à l’information. Objet const: appel seulement de fonctions membres const. INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Attribut constant Question: Comment initialiser un attribut constant? Réponse: Par le biais d’une liste d’initialisation class C { public: C() ; ... private: const int x; }; C::C() :x(0) { } INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données II. Le pointeur this Le mot this est un mot réservé contenant l’adresse de l’objet courant. Ce pointeur sert, entre autres, à retourner une référence à cet objet pour les appels en cascade. ex: a = b = c = d; Il ne faut jamais retourner une référence à une variable locale. INF1101 Algorithmes et structures de données
II - Surcharges d’opérateurs Surcharge des opérateurs binaires, unaires, opérateur assignation Commutativité et fonctions globales INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Introduction La surcharge (ou surdéfinition) d’opérateur est un concept qui permet d’implémenter une fonction ou un opérateur de différentes façons sans en changer la méthode d’appel (signature). INF1101 Algorithmes et structures de données
Besoin de la surcharge d’opérateurs En C/C++, il existe des variables de types simples int, float, double, sur lesquelles on peut effectuer des opérations arithmétiques. En C/C++, il n’existe aucun type de base string, d’où le besoin de créer une classe string pour traiter les chaînes de caractères. Cette classe string posséderait tous les opérateurs définis pour un type tel que un entier ou un double (+, [], +=, etc). INF1101 Algorithmes et structures de données
Application de la surcharge d’opérateurs string S1(“allo ”), S2(“le monde”), S3; S3 = S1 + S2; S3 = S1 + “a tous”; S2[1] = ‘a’; S2[3] = ‘r’; Cet exemple est rendu possible grâce à l’utilisation de la surcharge des opérateurs + et [] pour la classe string. INF1101 Algorithmes et structures de données
Surcharges d’opérateurs Consiste à redéfinir la fonctionnalité d’un opérateur tel que +, -, ou += pour une classe. Il faut bien comprendre le fonctionnement de l’opérateur. L’ordre de priorité est conservé. L’objet est toujours l’opérande de gauche. Les opérateurs gardent leur nombre de paramètres et ne peuvent avoir de paramètres par défaut. ( opérateurs binaires et unaires) Il n’est pas possible de créer de nouveaux opérateurs. INF1101 Algorithmes et structures de données
Surcharges d’opérateurs Pouvant être surchargés Ne pouvant être surchargés . :: ?: sizeof + - * / % ^ & | [] () ~ = < > += -= *= /= %= ^= &= ! ++ -- -> , >> << && != <= >= \= || <<= >>= == new delete INF1101 Algorithmes et structures de données
Surcharges d’opérateurs binaires Opérateur à deux opérandes. Il doit y avoir une opérande à gauche et à droite du symbole de l’opérateur. INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Opérateurs binaires string S1(“allo”), S2(“le monde”), S3; S3 = S1+S2; // équivalent à S1.operator+(S2); operator+() est une fonction membre de la classe string, car S1 est un objet de la classe string. Retourne un objet string. INF1101 Algorithmes et structures de données
La classe string : string.h class string { public: // Constructeurs string(char ch); string (const char* cstring=“”); ~string() {delete [] buffer}; // Opérations ... string operator + (const string&) const; private: int strLength; int bufferLength char *buffer; INF1101 Algorithmes et structures de données
Implémentation de l’opérateur + de string string string::operator+(const string &cstr) const { string Concat; Concat = *this; // surcharge de l’opérateur = Concat += cstr; // surcharge de l’opérateur += return Concat; } Remarque: l’opérateur + est défini en fonction de l’opérateur += INF1101 Algorithmes et structures de données
Implémentation de l’opérateur + de string (suite) Que se passe-t-il ? string S1(“allo”), S2; S2 = S1 + ”tous”; // ici il y a une conversion // implicite qui est réalisée S1.operator+(“tous”); Conversion implicite: On s’attend à une opérande de type string On a une opérande de type char* Il existe un constructeur qui accepte ce type de paramètre On construira donc un objet de type string en lui passant la chaîne On pourra alors appliquer l’opérateur aux deux opérandes INF1101 Algorithmes et structures de données
Conversion implicite de type Il faut se méfier des conversions implicites, C++ peut en faire à des endroits où on ne s’y attend pas On peut empêcher qu’un objet soit créé par une conversion implicite: il suffit d’ajouter explicit avant la déclaration du constructeur Ainsi, si on déclare le constructeur de la manière suivante: explicit string (const char* cstring=“”); on pourra empêcher la construction d’un string dans les cas suivants: string S1, S2; S = “allo”; S2 = S1 + “allo” INF1101 Algorithmes et structures de données
Implémentation de l’opérateur + de string (suite) Si on déclare le constructeur explicit, l’instruction S2 = S1 + “allo” n’est plus acceptée parce que l’opérateur n’accepte que des opérandes de type string. Dans ce cas, pour que l’instruction soit valide, il faut ajouter une autre définition de l’opérateur: INF1101 Algorithmes et structures de données
Implémentation de l’opérateur + de string (suite) class string { public: // Constructeurs explicit string(char ch); explicit string (const char* cstring=“”); ~string() {delete [] buffer}; // Opérations ... string operator + (const string&) const; string operator + (const char* cstr) const; private: int strLength; int bufferLength; char *buffer; INF1101 Algorithmes et structures de données
Commutativité et fonctions globales Ces derniers exemples de l’opérateur + prennent comme supposition que l’opérateur de gauche est un objet string. Cependant, ceci n’implique pas que cet opérateur est commutatif INF1101 Algorithmes et structures de données
Opérateur + non commutatif string S1(“allo”), F2(“le monde”), F3; char* A = “tous”; S3 = S1 + A; // équivalent à S1.operator+(A); Cet exemple utilise la surcharge: string operator + (const char*) const; Mais S3 = A + S1; //équivalent à A.operator+(S1)??? INF1101 Algorithmes et structures de données
Commutativité et fonctions globales (suite) Si l’on désire définir des opérateurs qui accepte autre chose qu’un objet string à gauche, et un objet string à droite de l’opérateur, il faut se définir des fonctions globales pour permettre cette commutativité. Exemple de surcharge globale de type char + string: string operator+(const char* A, const string& B); INF1101 Algorithmes et structures de données
Commutativité et fonctions globales (suite) Remarque: Si on définit l’opérateur + comme un opérateur global, et qu’on exclut pas la conversion implicite à partir d’un char* lors de l’appel du constructeur, on pourrait se contenter d’une seule définition: string operator+(const string& A, const string& B); INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Fonctions amies Problème dans certains cas: La fonction globale n’a pas le droit d’accéder au données privées de la classe Solutions: L’opérateur global accède aux données privées par le bien de fonctions membres publiques (peut être inefficace dans certains cas) On déclare la fonction globale comme étant « amie » friend string operator +(char*, const string &); INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Fonctions amies (suite) Attention: les fonctions amies violent le principe d’encapsulation. À moins de ne pouvoir faire autrement, il vaut mieux les éviter Dans le cas de la classe string, on peut l’éviter, en définissant une fonction globale qui prend en paramètre deux objets de type string: string operator+(const string&, const string&); Dans ce cas, il faut bien entendu que le constructeur accepte la conversion implicite Dans certains cas, on peut éviter de déclarer une fonction amie en n’utilisant que des fonctions membres de la classe pour accéder aux attributs de l’objet, si elles sont suffisantes pour la définition de l’opérateur INF1101 Algorithmes et structures de données
Surcharges d’opérateurs unaires Opérateur ayant un seul paramètre. L’unique argument est implicitement l’objet lui-même. Rational& operator ++ (); Rational& Rational::operator ++ () { numer+=denom; return (*this); Exemple d’utilisation: Rational F(2,3); F++; } INF1101 Algorithmes et structures de données
Surcharges de l’opérateur d’assignation (=) Si l’opérateur = n’est pas surchargé, le compilateur en génère un automatiquement. Cependant, l’assignation se fait attribut par attribut. L’opérateur = par défaut peut causer de sérieux problèmes si l’objet contient des membres construits par allocation dynamique. INF1101 Algorithmes et structures de données
Fonctions membres par défaut Dans une classe, même si le programmeur ne les définit pas, il y a toujours: Un constructeur par défaut s’il n’existe aucun autre constructeur. Un constructeur de recopie (attribut par attribut) La surcharge de l’opérateur = par défaut( attribut par attribut) est créée si une instruction fait appel à cet opérateur. Un destructeur par défaut INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données Attention ! Si votre classe a un attribut qui est un pointeur et alloue de l’espace mémoire dynamiquement, il faut absolument définir: Un constructeur de recopie; L’opérateur =; Et un destructeur; Et surtout ne pas utiliser les fonctions par défaut. INF1101 Algorithmes et structures de données
Exemple de surcharge d’opérateur = et de constructeur copie Dans la classe string, on a retiré le constructeur copie et la surcharge de l’opérateur = class string { public: string(char ch); string(const char*=“”); ~string(); . . . private: char *buffer; int length; }; INF1101 Algorithmes et structures de données
Exemple de surcharge d’opérateur = string a(“hola”),b; b=a; buffer length=4; a h o l a buffer length=4; b INF1101 Algorithmes et structures de données
Exemple de surcharge d’opérateur = string& string::operator=(const string &rhs) { if( this != &rhs) if(bufferLength < rhs.length()+1) delete []buffer; bufferLength=rhs.length()+1; buffer = new char[bufferLength]; } strLength=rhs.length(); strcpy(buffer,rhs.buffer); return *this; INF1101 Algorithmes et structures de données
INF1101 Algorithmes et structures de données IV – Membre statique Un attribut static n’existe qu’en une seule copie pour tous les objets d’une classe. Un attribut static est un espace commun à tous les objets instanciés. L’espace mémoire d’une variable de classe existe même si aucun objet n’a été déclaré. Cette variable est accessible via les fonctions membres ou par l’entremise de l’opérateur de résolution de portée :: . L’initialisation d’une variable de classe ne se fait pas dans le constructeur… INF1101 Algorithmes et structures de données
Fonction de classe static Une fonction de classe static ne peut accéder qu’aux membres static d’une classe. On peut appeler une fonction de classe sans déclarer d’objet par l’opérateur de résolution de portée :: . Les règles d’encapsulation demeurent les mêmes. INF1101 Algorithmes et structures de données
Variable de classe et fonction de classe statiques La classe Sphere possède la variable static nbSphere, qui conserve le nombre total de sphères créées dans le programme. class Sphere{ public: ... static int getNbSphere() {return nbSphere;}; static int nbSphere; }; // Initialisation dans sphere.cpp int Sphere::nbSphere = 0; Fonction de classe INF1101 Algorithmes et structures de données