Programmation en C++ Classes Définition et implémentation d'une classe Constructeurs, Données membres Fonctions membres Structuration du code C++
Introduction Nous allons illustrer le développement de code C++ sur une classe simple représentant un point dans l'espace 2D Nous allons commencer par les exigences que doit remplir notre classe : Point peut être créé à partir de ses coordonnées x, y Il est possible de calculer la distance à un autre point Il peut fournir (return) ses coordonnées x et y Un exemple de programme : A comparer avec les nombres entiers: int main() { // Créer deux points Point point1(1, 2) ; Point point2(2, 3); // Calculer et imprimer leur distance std::cout << point1.Distance(point2) << std::endl; ... } int main() { // Créer deux nombre int number1(5) ; int number2(10); // Calculer et imprimer leur « distance » std::cout << ( number1 – number2 ) << std::endl; ... }
La Programmation de la Classe On commence par la définition de la classe, où nous offrons seulement la déclaration des fonctions membres et des données membres Comme une déclaration de fonction, la définition de la classe est un contrat qui définit les fonctions que la classe doit remplir Définition de notre classe Point : fichier Point.h Mise en ouvre (définitions) des fonctions membres de la classe sont généralement fournis dans un fichier séparé, appelé aussi l'implémentation de la classe Implémentation de notre classe Point : fichier Point.cxx
Définition de la Classe La définition de la classe : class class-name { class-body }; Le corps de la classe (class-body) consiste en déclaration de méthodes et données membres de la classe : Les fonctions qui servent à manipuler l'objet de l'extérieur se trouvent dans l'espace « public » Les données membres se trouvent dans l'espace « private » (Rapp el: encapsulation) Dans l'espace « private » on peut trouver aussi les fonctions qui sont accessibles seulement par la classe elle-même class class-name { public: // Fonctions pour construire l'objet // Fonctions pour manipuler l'objet // Fonctions pour accéder à l'état de l'objet private: // Fonctions pour utilisation intérieure // Données membres };
La définition de la classe Point class class-name { public: // Fonctions pour construire l'objet // Fonctions pour manipuler l'objet // Fonctions pour accéder à l'état de l'objet private: // Données membres }; Fichier Point.h class Point { public: // Fonctions pour construire l'objet Point(float x, float y); Point(); // Fonctions pour manipuler l'objet float Distance(Point point); // Fonctions pour accéder à l'état de l'objet float GetX(); float GetY(); private: // Données membres float m_x; float m_y; }; Le choix des fonctions de membre est déterminé par les exigences: Point peut être créé à partir de ses coordonnées x, y Il est possible de calculer la distance à un autre point Il peut fournir (return) ses coordonnées x et y
L'implémentation de la classe Fonctions Membres La définition des fonctions membres pour manipuler l'objet : Les fonctions de la classe Point : return-type class-name::function-name { function-body } Fichier Point.cxx float Point::Distance(Point point) { /// Calculer la distance du point donné float x_diff = m_x – point.m_x; float y_diff = m_y – point.m_y; return sqrt(x_diff*x_diff + y_diff*y_diff); } Fichier Point.h Fichier Point.cxx float Distance(Point point) Point(); float GetX(); float GetY() ; float Point::GetX() { return m_x; } float Point::GetY() { return m_y; }
Constructeurs Le constructeur est une fonction membre spéciale qui sert à construire l'objet : Fichier Point.h Point(float x, float y); class-name::class-name(arguments-list) : data-member-initialisation { function-body } Les constructeurs de la classe Point à partir des coordonnées x, y: La liste d'initialisation (data-membre- initialisation) comprend toutes les données membres de la classe dans l'ordre où elles sont déclarées dans la définition de la classe Elle n'est pas obligatoire, mais si on ne la fournit pas, elle est accomplie par le compilateur en utilisant les valeurs au hasard Une classe peut avoir plusieurs constructeurs Fichier Point.cxx Point::Point(float x, float y) : m_x(x), m_y(y) { /// Le constructeur à partir des coordonnées /// x, y }
Constructeur par défaut Le constructeur par défaut est un constructeur spécial qui n'a aucun argument : Fichier Point.h Point(); class-name::class-name() : initialisation-list { function-body } Le constructeur par défaut de la classe Point : Les données membres sont initialisées à des valeurs par défaut Fichier Point.cxx Point::Point() : m_x(0), m_y(0) { /// Le constructeur par défaut /// (Le point est initialisé au centre) }
Utilisation des classes La classe peut être utilisée par exemple dans une fonction main() de programme ou dans une autre classe Fichier main.cxx #include “Point.h” int main() { // Créer deux points Point point1; Point point2(2, 3); // Calculer et imprimer leur distance std::cout << point1.Distance(point2) << std::endl; ... }
Structuration du code C++ ... Le code est habituellement structuré par des classes La définition de la classe est séparée de l'implantation des méthodes, alors on a 2 fichiers par classe Fichier en-tête – extension: .h (.hh) Fichier d'implantation – extension: .cxx (.cpp, .cc, .C, ...) Point. Le fichier en-tête est parfois aussi appelé l'interface de classe; qu'il ne faut pas confondre avec le même terme utilisé pour des classes abstraites Point.h Point.cxx main.cxx class Point { public: Point(float x, float y); float Distance(Point point); private: float m_x; float m_y; }; #include “Point.h” Point::Point(float x, float y) : m_x(x), m_y(y) {} float Point::Distance(Point point) { float x_diff = m_x – point.m_x; float y_diff = m_y – point.m_y; return sqrt(x_diff*x_diff + (x_diff*x_diff); } #include “Point.h” #include <iostream> int main() { Point p1(0, 0); Point p2(2, 3); std::cout << p1.Distance(p2) << std::endl; return 0; }
... Structuration du code C++ Les classes peuvent être structurées dans les paquets, les fichiers sont alors placés dans les répertoires par paquet Souvent le répertoire est divisé dans 2 sous-répertoires: include (*.h), src (*.cxx) La conception doit s'occuper des relations (les dépendances) entre les paquets Il faut définir la hiérarchie des paquets Il faut éviter les dépendances circulaires Le style du codage peut varier d'un projet à l'autre mais la bonne pratique est d'en adopter un et le suivre constamment: L'espace public précède l'espace private Données membres commencent par m_ Les fonctions membres commencent par une lettre majuscule ...