Les classes Introduction aux Langages Orientés Objets Qu’est-ce qu’un objet ? Propriétés Notion d’héritage Notion de polymorphisme Les classes en C++ Interface Implantation Constructeur / Destructeur
Langage Orienté Objet : qu’est-ce qu’un objet ? Un objet est une entité informatique comprenant : des données membres (ou champs ou attributs ou variables d’instances) des fonctions membres (ou méthodes ou routines) On appelle encapsulation le regroupement des variables et des fonctions au sein d'une même entité. Ex : un objet vecteur est composé de trois réels et d’opérations telles que la translation, la norme, le produit scalaire … L'accès aux données et méthodes peut être réglementé : . Fonctions membres Données membres Partie publique Vision interne Vision externe Partie privée
Objet : exemples (notation UML) DeuxRoues m_tailleRoues m_nbVitesses m_couleur m_poids Accélérer() Freiner() ChangerVitesse() GetCouleur() GetPoids() Nom de la classe CompteBancaire m_numéro m_solde m_propriétaire Créditer() Débiter() Fermer() Numéro() Solde() Propriétaire() Vision interne Données membres ou attributs Vision interne Fonctions membres ou méthodes Vision externe Vision externe
Propriétés d’un objet Un objet possède un état : L’état correspond à la valeur de ses attributs à un instant donné. Il peut varier au cours du temps. Un objet est décrit par une classe : Une classe est un prototype qui définit des attributs et des méthodes communes à tous les objets d'une certaine nature. C’est donc un modèle utilisé pour créer plusieurs objets présentant des caractéristiques communes. Un objet possède une identité : Les objets peuvent être distingués grâce à leurs existences inhérentes et non grâce à la description des propriétés qu'ils peuvent avoir. Deux objets peuvent être distincts même si tous leurs attributs ont des valeurs identiques. Ne pas confondre instance d'objet et classe d'objets Une instance de classe fait référence à une chose précise Une classe désigne un groupe de choses similaires Ex : Le vélo de mon voisin et le mien sont deux instances de la classe vélo, même s’ils sont strictement identiques
Notion d’héritage L'héritage est un principe propre à la POO qui permet de créer une nouvelle classe à partir d'une classe existante. La classe nouvellement créée, dite classe dérivée, contient les attributs et les méthodes de la classe dont elle dérive, auxquelles s’ajoutent de nouveaux attributs et de nouvelles méthodes propres à la classe dérivée. L’héritage permet donc de définir une hiérarchie de classes : La classe de base est une classe générique. Les classes dérivées sont de plus en plus spécialisées classe de base ou classe mère ou classe parente Deux roues classes dérivées ou classes filles Sans moteur A moteur Vélo Patinette Moto Scooter Mobylette
Notion de polymorphisme Une classe dérivée peut fournir une nouvelle définition d’une méthode d'une classe parent car elle peut avoir besoin de réagir différemment à l'appel de cette méthode. Cette redéfinition substituera une méthode à une autre : c’est la spécialisation. La notion de polymorphisme signifie que, la même opération pouvant se comporter différemment sur différentes classes de la hiérarchie, il est possible d'appeler la méthode d'un objet sans se soucier de son type intrinsèque. Ceci permet de faire abstraction des détails des classes spécialisées d'une famille d'objet, en les masquant par une interface commune (qui est la classe de base). Velo m_typePedale GetTypePedale() virtual Accélérer() virtual Freiner() virtual ChangerVitesse() DeuxRoues m_tailleRoues m_couleur m_poids m_nbVitesses virtual Accélérer() virtual Freiner() virtual ChangerVitesse() GetCouleur() GetPoids() La fonction Accélérer() n’est pas la même pour un Velo et une Moto. La redéfinition de cette fonction dans chacune des sous-classes entraînera un comportement différent suivant que le DeuxRoues est un Velo ou une Moto. Moto m_moteur m_boiteVitesse FairePlein() AllumerClignotant() virtual Accélérer() virtual Freiner() virtual ChangerVitesse()
Programmation orientée objet vs programmation séquentielle Avantages : Programmes plus faciles à maintenir Si on décide de modifier la structure des données dans un programme séquentiel, presque tout le code est à réécrire Programmation plus claire : les fonctions sont rattachées à un type de données Modularité accrue -> possibilité de ré-utiliser le code Inconvénients : Le programme résultant peut être moins efficace (en termes de taille mémoire et de rapidité)
Classe : interface C’est la description de la structure interne de la classe class Cercle { Visibilité des membres : public : membres accessibles à tous private : membres accessibles à partir de la classe ; accès impossible par l’extérieur protected : membres accessibles à partir de la classe et des classes dérivées ; accès impossible par l’extérieur protected : float m_cX, m_cY; float m_r; public : void deplace(float dx, float dy); void zoom(float z); float surface(); Vision interne Vision externe };
Classe : implantation C’est la définition des fonctions associées Interface de la classe cercle class Cercle { protected : float m_cX, m_cY; float m_r; public : void deplace(float dx, float dy); void zoom(float z); float surface(); }; void Cercle::deplace(float dx, float dy) { m_cX += dx; m_cY += dy; } void Cercle::zoom(float z) m_r *= z; float Cercle::surface() return 3.14 * m_r * m_r; Opérateur de portée
Classe : instanciation Interface de la classe cercle class Cercle { protected : float m_cX, m_cY; float m_r; public : void deplace(float dx, float dy); void zoom(float z); float surface(); }; Instancier une classe permet de créer un objet (analogue à une déclaration de variable) Instanciation statique de l’objet c de type cercle int main() { Cercle c; c.deplace(50, 0); float s = c.surface(); c.zoom(1.5); c.m_cX = 30; // Impossible c. deplace(20); // Impossible } Accès aux membres Implantation de la classe cercle void Cercle::deplace(float dx, float dy) { m_cX += dx; m_cY += dy; } void Cercle::zoom(float z) m_r *= z; float Cercle::surface() return 3.14 * m_r * m_r;
Organisation (usuelle) des fichiers Par convention, l'extension d'un fichier contenant du code C est .cpp, .c++ , .cc , .cxx ou .C L'extension d'un fichier de déclarations, appelé header, est .h Par convention, on crée un fichier .cpp et un .h par classe. cercle.h cercle.cpp prog.cpp class Cercle { protected : float m_cX, m_cY; float m_r; public : void deplace(float dx, float dy); void zoom(float z); float surface(); }; #include “cercle.h” void Cercle::deplace(float dx, float dy) { m_cX += dx; m_cY += dy; } void Cercle::zoom(float z) m_r *= z; float Cercle:: surface() return 3.14 * m_r * m_r; #include "cercle.h" int main() { Cercle c; c.deplace(50, 0); float s = c.surface(); c.zoom(1.5); return 0; } Par convention, les noms de classe commencent par une majuscule, les données membres par _ ou m_, les fonctions membres par une minuscule.
Constructeurs de classe Le constructeur est une fonction membre qui sert à initialiser les données membres de l’objet Systématiquement appelé quand un objet est instancié. N’a pas de type de retour Porte le nom de l’objet Une même classe peut avoir plusieurs constructeurs Constructeurs particuliers : constructeur par défaut Ne contient aucun argument Automatiquement généré si aucun constructeur n’est défini A définir explicitement dans le cas contraire constructeur de copie Contient comme argument un objet du même type Sert à créer des clones d’objets Automatiquement généré par le compilateur (copie membre à membre) mais pas toujours satisfaisant
Constructeurs de classe : exemple cercle.h cercle.cpp prog.cpp class Cercle { public : Cercle(); // Constructeur par défaut Cercle(float x, float y, float r); Cercle(const Cercle& c); protected : float m_cX, m_cY; float m_r; void deplace(float dx, float dy); void zoom(float z) {m_r *= z;} float surface() {return 3.14 * m_r * m_r;} }; #include “cercle.h” Cercle::Cercle() { m_cX = m_ cY = 0; m_r = 1; } Cercle::Cercle(float x, float y, float r) m_ cX = x; m_ cY = y; m_r = r; Cercle::Cercle(const Cercle& c) m_ cX = c. m_ cX; m_ cY = c. m_ cY; m_r = c. m_r ; void Cercle::deplace(float dx, float dy) m_ cX += dx; m_cY += dy; #include <iostream.h> #include "cercle.h" int main() { Cercle c1; Cercle c2(2.5, 6, 0.1); Cercle c3(c1); // clone de c1 Cercle c4 = c1; // clone de c1 Cercle c5(10); // Impossible return 0; }
Destructeur de classe Fonction membre systématiquement appelée juste avant la destruction d’un objet Porte le nom de la classe et est précédé de ~ Pas de type de retour Pas d’arguments Un seul par classe Permet de libérer les ressources cercle.h cercle.cpp prog.cpp class Cercle { public : Cercle(); // Constructeur par défaut Cercle(float x, float y, float r); Cercle(const Cercle& c); ~Cercle(); // Destructeur protected : float m_cX, m_cY; float m_r; void deplace(float dx, float dy); void zoom(float z) {m_r *= z;} float surface() {return 3.14 * m_r * m_r;} }; #include “cercle.h” Cercle::Cercle() { m_cX = m_ cY = 0;m_r = 1; } Cercle::Cercle(float x, float y, float r) m_ cX = x; m_ cY = y; m_r = r; Cercle::Cercle(const Cercle& c) m_ cX = c. m_ cX; m_ cY = c. m_ cY; m_r = c. m_r ; Cercle::~Cercle() // Libération des ressources void Cercle::deplace(float dx, float dy) m_cX += dx; m_cY += dy; #include <iostream.h> #include "cercle.h" int main() { Cercle c1; Cercle c2(2.5, 6, 0.1); return 0; // Le destructeur est appelé // pour c1 puis pour c2. }
Vocabulaire Variable : associe un nom (un symbole) à une valeur qui peut éventuellement varier au cours du temps ; une variable est d’un type donné, défini une fois pour toute (type prédéfini dans le langage ou créé par le développeur). Encapsulation : regroupement des variables et des fonctions au sein d'une même entité appelée « classe ». Classe : prototype qui définit des attributs et des méthodes communes à tous les objets d'une certaine nature. Interface de classe : description de la structure interne de la classe incluant une liste des données membres et le prototype des fonctions membres ; dans un « .h ». Implantation de classe : définition (code) des fonctions déclarées dans l’interface de classe ; dans un « .cpp ». Instanciation d’un objet : permet de créer un objet d’un type donné ; analogue à une déclaration de variable. Héritage : permet de définir une hiérarchie de classe, chaque classe fille héritant des méthodes et des données de son/ses antécédent(s). Polymorphisme : deux objets héritant une même méthode d'une classe parente, peuvent réagir de façon différente à l'appel de cette méthode et, à cette fin, redéfinir la méthode. Il est ensuite possible d'appeler la méthode d'un objet sans se soucier de son type intrinsèque.