Concepts orientés objets

Slides:



Advertisements
Présentations similaires
La programmation orientée objet avec Java L3-MIAGE Plan
Advertisements

Premier programme en C :
La boucle for : init7.c et init71.c
Formation universitaire à .NET: Introduction à C#
Cours n° 8 Conception et Programmation à Objets
(Classes prédéfinies – API Java)
C.
Leçon 3 : Héritage IUP 2 Génie Informatique
Introduction à la POO: Les classes vs les objets
Principes de programmation (suite)
Programmation orientée objet
Introduction à la programmation (420-PK2-SL) cours 12 Gestion des applications Technologie de linformation (LEA.BW)
Leçon 6 : Structures de données dynamiques IUP 2 Génie Informatique Méthode et Outils pour la Programmation Françoise Greffier.
Bibliothèque standard du C++
8PRO100 Éléments de programmation Allocation dynamique de la mémoire.
Principes de programmation (suite)
IFT-2000: Structures de Données Listes chaînées Dominic Genest, 2009.
Introduction au paradigme objet Concepts importants surcharge (overload) redéfinition (override) Définition d’une classe Définition des attributs.
© 2007 P. Van Roy. All rights reserved. FSAB1402: Informatique 2 Le Langage Java et les Exceptions Peter Van Roy Département dIngénierie Informatique,
Les Classes les structures en C (struct) regroupent des variables : structuration de l'analyse mais problèmes de cohérence problèmes de sécurité d'accès.
77 Utilisation des classes (suite). 7-2 Objectifs A la fin de ce cours, vous serez capables de : Définir des méthodes surchargées dans une classe Fournir.
Quest-ce quune classe dallocation? Une classe dallocation détermine la portée et la durée de vie dun objet ou dune fonction.
Langage Oriente Objet Cours 2.
Leçon 2 : Surcharge des opérateurs IUP 2 Génie Informatique Méthode et Outils pour la Programmation Françoise Greffier Université de Franche-Comté.
Les pointeurs Modes d’adressage de variables. Définition d’un pointeur. Opérateurs de base. Opérations élémentaires. Pointeurs et tableaux. Pointeurs et.
Test et débogage Tests unitaires. Gestion d’erreurs. Notion d’état, de pré-condition et de post-condition. Assertion. Traces de programme. Débogueur et.
Structures de données IFT-2000
Structures de données IFT Abder Alikacem La classe string Département dinformatique et de génie logiciel Édition Septembre 2009 Département dinformatique.
Structures de données IFT-10541
Programme de baccalauréat en informatique Programmation Orientée Objets IFT Thierry EUDE Module 7 : Classes et fonctions paramétrables Département.
Introduction au paradigme orienté-objet (suite)
Chapitre 9 Les sous-programmes.
Types de données abstrait et mécanismes d'encapsulation
8PRO100 Éléments de programmation Les types composés.
COURS DE PROGRAMMATION ORIENTEE OBJET :
Standard Template Library
Leçon 1 : notion dobjet IUP Génie Informatique Besançon Méthode et Outils pour la Programmation Françoise Greffier Université de Franche-Comté.
Programme de baccalauréat en informatique Programmation Orientée Objets IFT Thierry EUDE Module 6. Gestion des erreurs et des exceptions : Fonctionnement.
Structures de données IFT-10541
Classes et objets Types de données abstraits, programmation orientée objet, classes, objets,
Structures de données IFT-2000 Abder Alikacem Concepts orientés objet Édition Septembre 2009 Département dinformatique et de génie logiciel Département.
Plan cours La notion de pointeur et d’adresse mémoire.
La notion de type revisitée en POO
La Modélisation Orientée Objet Concevoir un programme : modélisation du problème à résoudre Notion de programme : machine de Turing Pouvoir d’expression.
7ième Classe (Mardi, 24 novembre) CSI2572. Devoir 3 ?
Labo 4 : Les structures et les entrées et sorties
Tutorat en bio-informatique
5ième Classe (Mercredi, 19 octobre) Prog CSI2572.
Tutorat en bio-informatique Le 14 novembre Au programme… Les objets –Propriétés (attributs) –Constructeurs –Méthodes.
Introduction au langage C Fonctions et Procédures
Les classes présenté par: RAHMOUNE RIME / ZEKRI SELMA.
Les types composés Les enregistrements.
Les surcharges d'opérateurs
Conception de Programmes - IUT de Paris - 1ère année – Cours 8 – Les entrées/sorties Comment fonctionnent les opérateurs > pour les types élémentaires.
Les classes Introduction aux Langages Orientés Objets
Cours 4 (14 octobre) Héritage. Chapitre III Héritage.
Conception de Programmes - IUT de Paris - 1ère année Conception de Programmes Objectifs et organisation du cours Introduction à la P.O.O.
Chapitre VII Techniques plus avancées à travers le concept de classe.
Héritage Conception par Objet et programmation Java
Conception de Programmes - IUT de Paris - 1ère année Quelques éléments du langage C++ Les références La surcharge de fonctions Les fonctions «
8PRO107 Éléments de programmation Les adresses et les pointeurs.
Langage de Programmation Orientée Objet : C++
Conception de Programmes - IUT de Paris - 1ère année Les classes Introduction Déclaration d’une classe Utilisation d’une classe Définition des.
C++ BY AURÉLIEN MODULO MARION. PLAN DES TROIS PRÉSENTATIONS C++ avancé C++ orienté objet Bases de C++
Transcription de la présentation:

Concepts orientés objets Programme de baccalauréat en informatique Programmation Orientée Objets IFT-19946 Thierry EUDE Module 2 : Concepts orientés objets Département d’informatique et de génie logiciel

Département d'informatique - Université Laval 22/04/2017 2. Concepts orientés objets 2.1 Introduction Département d'informatique - Université Laval H2007

Un objet Un objet possède 2 types de propriétés : Statiques : état, attributs. Dynamiques : comportements, services. Exemple : le chat de ma voisine Statiques : son nom (Phillipon) son poids (18 livres – je sais il est gros...) sa couleur (noir et blanc) Dynamiques : il miaule quand il a faim il se couche sur son cousin près du sofa il mange des mouches

Une classe Phillipon est un digne représentant de la race des chats. Phillipon est une instance de la classe des chats. Tous les chats ont des propriétés communes : ils miaulent (propriété dynamique) ils ont une moustache (propriété statique) etc. Chat : classe représentant un ensemble d’objets ayant : des attributs semblables des comportements semblables.

Vers une hiérarchie de classes Si on poursuit l’analogie, il existe : Différents, mais partagent tous des caractéristiques : ils mangent de la viande leurs griffes peuvent se rétracter leurs molaires sont coupantes ils ont une moustache

Vers une hiérarchie de classes Généralisation: races chat, lion et tigre => super-race nommée félins. La super-race définit : des propriétés des comportements valides autant pour les chats que pour lions et tigres. En termes informatiques, la classe Félin correspond à une super-classe des classes Chat, Lion et Tigre. Chat, lion, tigre : classes dérivées de la classe Félin héritent des propriétés et des comportements de leur super-classe. C’est le concept d’héritage.

Vers une hiérarchie de classes Extension du concept d’héritage : arbre d’héritage. On s’attend à certaines caractéristiques de Phillipon Il est une instance (objet) de la classe Chat ( miauler, dormir, moustaches). On s’attend à ce qu’il puisse se mouvoir non pas parce qu’il est un chat, mais parce qu’il appartient à la classe Animal, donc par héritage.

Polymorphisme Les chats, les serpents et les poissons partagent tous un comportement commun hérité de la classe des animaux : ils ont la capacité de se mouvoir. Tous le font, mais chacun à sa manière : le chat marche le serpent rampe le poisson nage Si on donne l’ordre de se mouvoir, chaque animal va pouvoir répondre à cet ordre, à sa manière propre. polymorphisme

Encapsulation Phillipon miaule, marche, mange : Nous connaissons les manifestations extérieures du miaulement, mais la façon dont le son est produit nous est masqué. Chat = abstraction On ne montre seulement que quelques comportements. Une interface représente cette abstraction. Énonce les services offerts Les détails de fonctionnement sont cachés. Emphase sur la compréhension des éléments importants, sans se soucier de l’implantation.

Synthèse 1 2 3 4 5

Département d'informatique - Université Laval 22/04/2017 2. Concepts orientés objets 2.1 Introduction 2.2 LE MODÈLE OBJET Département d'informatique - Université Laval H2007

Les composantes de l’objet Un objet a : un état, un comportement une identité unique. La structure et le comportement d'objets semblables sont définis dans la classe qui leur est commune. Les termes instance, occurrence et objet sont synonymes.

Les composantes de l’objet État de l'objet : Valeurs de ses attributs ou de l'information qu'il contient. Comportement de l'objet Ensemble des opérations que l'on peut effectuer sur celui-ci. Identité de l'objet Deux objets peuvent être exactement dans le même état, mais sont différents de part leur identité unique ex.: adresse en mémoire.

Éléments de définitions de l’objet “Chose” tangible et/ou visible “Chose” que l'on peut concevoir intellectuellement Rôles (ex. : mère, professeur, politicien) Interfaces usagers et matériel du système Événements et transactions Personnes et emplacements Classes de fondement: chaîne, vecteur, liste chaînée, dictionnaire, date... Organisations

La classe ? Objet = entité discrète qui existe dans le temps et dans l'espace. Classe = abstraction qui n’existe que dans les programmes. doit représenter un ensemble d'objets qui partagent une structure commune et un comportement commun. définit les opérations permises sur les objets de la classe. les états qu’ils peuvent prendre (transitions d’états).

Un objet doit être valide de sa création jusqu’à sa destruction. La classe et ses objets La classe responsable d’assurer la validité de tous les objets créés à partir d’elle-même. Un objet doit être valide de sa création jusqu’à sa destruction. ne pas permettre l’accès direct aux attributs! La théorie du contrat pourrait gérer cette validité (nous y reviendrons).

Interface et implémentation L'interface d'une classe définit ce qui est vu de l'extérieur. renforce la notion d'abstraction en ne montrant que ce qui est nécessaire. contient principalement les déclarations de toutes les opérations applicables sur les instances de cette classe. L'implémentation d'une classe est ce qui est caché à l'intérieur, principalement le code réalisant les opérations définies dans l'interface.

Interface d’une classe : exemple class Pile { public: Pile (int capacite); ~Pile (); int pop (); void push (int); int top () const; void init (); private: ... };

Synthèse Objet Classe Interface

Département d'informatique - Université Laval 2. Concepts orientés objets 2.1 Introduction 2.2 Modèle objet 2.3 La classe Département d'informatique - Université Laval

Problèmes avec une structure Structure vs Classe Problèmes avec une structure Exemple : Date struct Date { int m_jour; int m_mois; int m_annee; }; Date = nouveau type. Variables déclarées à l'intérieur de la structure  attributs Il est possible d'accéder directement aux attributs.

Exemple avec une structure struct Date { int m_jour; int m_mois; int m_annee; }; void main() { Date uneDate; // --- date valide uneDate.m_jour = 30; uneDate.m_mois = 3; uneDate.m_annee = 1965; // --- date invalide uneDate.m_mois = 2; }

Problème avec une structure Accès aux attributs non contrôlée par la structure. Possibilité de non-initialisation. Possibilité de mauvaise assignation. Pas de garantie sur la validité des données. Si changement de l'implantation de Date … Exemple : On veut conserver un entier correspondant au nombre de secondes écoulées depuis un moment précis, … revoir l'utilisation de la structure un peu partout dans le code.

Implémentation d’une classe : les étapes Déclarer les attributs dans la section privée de la définition de la classe. Déclarer les méthodes dans la section publique de la définition de la classe. Définir l’implantation des méthodes après la définition de la classe dans un fichier séparé (pour le C++). Utiliser la classe en créant des objets de ce type dans un programme.

Déclarer les attributs État d’un objet : décrit par ses attributs: class Date { // ... private: int m_jour; int m_mois; int m_annee; }; Attributs déclarés privés On ne peut y accéder directement.

Accès direct impossible !!! Les attributs sont déclarés privés. Exemple : classe Date class Date { private: int m_jour; int m_mois; int m_annee; }; main() { Date uneDate; uneDate.m_jour = 30; uneDate.m_mois = 3; uneDate.m_annee = 1965; } Accès direct impossible !!! Les attributs sont déclarés privés.

Déclarer puis implanter les méthodes Rôle des méthodes de la classe : La classe Date n’accepte pour valeur qu’un sous-ensemble des valeurs possibles. contrôler l’assignation des valeurs sur les champs. Exemple: 31/02/1965 n’est pas une date valide.

Fonctions vs méthodes Nous parlons ici de programmation orientée objet. struct Date { int m_jour; int m_mois; int m_annee; }; void initialise(Date& date, int jour, int mois, int annee); class Date { public: void initialise(int jour, int mois, int annee); private: int m_jour; int m_mois; int m_annee; };

Fonctions vs méthodes Fonction, exemple : void initialise(Date& date, int jour, int mois, int annee) { date.m_jour = jour; date.m_mois = mois; date.m_annee = annee; } La fonction doit avoir les valeurs à assigner ET la date sur laquelle travailler. main() { Date uneDate; initialise(uneDate, 30, 3, 1965); } La date sur laquelle travailler.

Fonctions vs méthodes Méthode, exemple : void Date::initialise(int jour, int mois, int annee) { m_jour = jour; m_mois = mois; m_annee = annee; } Accès direct aux attributs de l'objet courant. main() { Date uneDate; uneDate.initialise(30, 3, 1965); } L'objet sur lequel appliquer l'initialisation.

Fonctions vs méthodes Les différences : void initialise(Date& date, int jour, int mois, int annee) { date.m_jour = jour; date.m_mois = mois; date.m_annee = annee; } La fonction est globale. Accès direct aux attributs de la structure. void Date::initialise(int jour, int mois, int annee) { m_jour = jour; m_mois = mois; m_annee = annee; } La méthode a une portée limitée à la classe Date. Accès direct aux attributs de l'objet courant.

void Date::initialise(int j, int m, int a) Objet courant On peut référer à l'objet courant explicitement en général ce n'est pas de mise. En C++, this permet de référer au pointeur à l'objet courant. void Date::initialise(int j, int m, int a) { this->m_jour = j; this->m_mois = m; this->m_annee = a; }

… visibilité par défaut Structure et Classe Différence entre une structure et une classe en C++ ? … struct Date { int m_jour; int m_mois; int m_annee; }; class Date { int m_jour; int m_mois; int m_annee; }; … visibilité par défaut Structure : visibilité publique. Classe : visibilité privée.

Structure et Classe: différences? La classe peut avoir des méthodes et des attributs avec la visibilité explicite : public, private… Norme : Toujours spécifier la visibilité explicitement.

Synthèse Structure - 1 2 Classe

Initialisation création d'un objet, constructeur. ses attributs doivent être initialisés pour que celui-ci soit dans un état cohérent. constructeur. constructeur = méthode spéciale. a le même nom que la classe. est automatiquement appelé à la création d'un objet de la classe. méthode qui n'a pas de type de retour ne retourne pas de valeur.

Par contre, on peut faire : Les constructeurs Protection des attributs : Date d; d.m_jour = 31; d.m_mois = 3; d.m_annee = 1965; Impossible ! Par contre, on peut faire : Date d; d.initialise(31,3,1965); Problème : pendant un certain temps l'objet Date n'est pas correctement initialisé. Solution: utiliser la méthode spéciale qu'est le constructeur

Les constructeurs class Date { public: Date(int jour, int mois, int annee); ... }; Date::Date(int jour, int mois, int annee) m_jour = jour; m_mois = mois; m_annee = annee; } Constructeur automatiquement appelé lorsqu’un objet Date est déclaré: Date d(1, 1, 1997); Par contre, on ne peut plus écrire: Date d;

Les constructeurs Il est possible d’avoir plusieurs constructeurs dans une même classe. Caractéristique du langage : Plusieurs méthodes du même nom = surcharge de méthode. Lorsqu'une fonction surchargée est appelée, le compilateur sélectionne la bonne fonction selon les arguments: nombre, type, ordre..

Les constructeurs On peut vouloir en même temps : un constructeur qui accepte la date complète un constructeur par défaut constructeur auquel on ne fournit pas de donnée. Exemple : class Date { public: Date(); Date(int jour, int mois, int annee); … };

Les constructeurs Mais aussi que : Le constructeur par défaut de la classe Date puisse prendre la date courante du système en guise de date. Un constructeur permettant d’initialiser une date à partir d’une chaîne de caractères d’un format déterminé: Date(const std::string& txtDate);

Les constructeurs : exemple class Date { public: Date(); Date(int jour, int mois, int annee); Date(const std::string& txtDate); }; Constructeurs dans l’ordre Date e; Date d(31,3,1997); Date f("31 mars 1997"); Date g(31, "mars", 1997); Date vDate[10]; Date(int,string,int); n’existe pas! Date() appelé 10 fois

Construction des sous-objets Utilisez une liste d’initialisation: construire tous les sous-objets avant le corps du constructeur parce que lorsqu'on y est rendu, ces objets sont déjà construit, i.e. on a déjà appelé leur constructeur par défaut. Date::Date(int jour, int mois, int annee) { // Les attributs ont déjà été initialisés par défaut. m_jour = jour; m_mois = mois; m_annee = annee; } // Version préférable Date::Date(int jour, int mois, int annee) : m_jour(jour), m_mois(mois), m_annee(annee) { } Liste d'initialisation

Construction des sous-objets Exemple 2 : Message::Message(const string& expediteur, const string& destinataire, const Date& dateRecu, const string& titre, const string& message) : m_expediteur(expediteur), m_destinataire(destinataire), m_dateRecu(dateRecu), m_titre(titre), m_message(message) { } Construire un objet avec des valeurs par défaut pour ensuite les changer avec les valeurs désirées. Un appel de plus est fait inutilement.

Le destructeur méthode particulière de la classe. porte le même nom que la classe mais précédé par un tilde ~. est exactement le complément du constructeur Le constructeur initialise les attributs et alloue des ressources s’il y a lieu, le destructeur libère les ressources si nécessaire. Ne détruit pas l'objet: il fait le ménage à l’intérieur avant la destruction.

Le destructeur Ne reçoit pas de paramètre et ne retourne pas de valeur. Un seul par classe. Facultatif: Le compilateur en génère un qui ne fait rien. Est utile lorsque l’objet est responsable de ressources allouées dynamiquement. Ne pas implanter de destructeur s'il n'y a pas de désallocation de ressource.

Constructeur / Destructeur class Date { public: Date(int j, int m, int a); ~Date(); private: int m_jour; int m_mois; int m_annee; }; Date::Date(int j, int m, int a) : m_jour(j), m_mois(m), m_annee(a) } Date::~Date() Date déclarée Constructeur appelé void main() { Date d(1, 1, 1965); } Initialisation seulement Sortie du «scope», destructeur appelé Rien à faire? => ne pas implanter

Constructeur / Destructeur string déclarée, constructeur appelé class string { public: string(const char* strP); ~string(); private: char *m_strP; }; string::string (const char* strP) m_strP = new char[strlen(strP)+1]; strcpy (m_strP, strP); } string::~string() delete [] m_strP; void main() { string s("Bonjour"); } Sortie du «scope», destructeur appelé Initialisation et allocation de ressources. Désallocation de ressources

Synthèse Constructeur : Destructeur :

2.4 Méthodes par catégorie 2. Concepts orientés objets 2.1 Introduction 2.2 Élément du modèle objet 2.3 La classe 2.4 Méthodes par catégorie Département d'informatique - Université Laval

Méthodes par catégorie Accès Assignation Comparaison Utilitaires Statiques Optimisées

Méthode d’accès class Date { public: ... int reqJour () const; int reqMois () const; int reqAnnee () const; }; Accéder à l’information sans modifier  méthodes constantes.

Méthodes constantes : protection des données méthodes d’accès en lecture vs méthodes qui modifient l’état de l’objet. traitement spécial on doit les déclarer constantes. En C++, mot clé : const Indique l'intention de ne pas modifier l’objet dans cette méthode

Méthodes constantes : exemple class Date { public: ... int reqJour () const; int reqMois () const; int reqAnnee () const; }; Le mot-clé const se retrouve dans l’interface et dans l’implantation int Date::reqJour () const { return m_jour; } Le compilateur fera la vérification que les attributs de l’objet ne seront pas modifiés dans cette méthode.

Méthodes constantes Outil permettant d’améliorer la qualité du code de façon très importante il force la classification. Il faut adhérer à cette façon de faire si on désire partager du code et utiliser des librairies qui ont adhéré à cette norme. La librairie standard adhère à cette norme.

Méthodes constantes : exemple class Date { public: void imprime(); private: int m_jour; int m_mois; int m_annee; }; void Date::imprime() { cout << m_jour << ":" << m_mois << ":" << m_annee; } Ne compile pas! le compilateur ne peut deviner que vous ne modifiez pas la date en l’imprimant... class Message { public: void imprime() const; private: string m_expediteur; Date m_dateRecu; }; void Message::imprime() const { cout << m_expediteur << endl << m_dateRecu.imprime(); }

Méthodes d’assignation Accès Méthodes d’assignation class Date { public: void asgJour (int jour); void asgMois (int mois); void asgAnnee (int annee); private: int m_jour; int m_mois; int m_annee; }; void Date::asgJour(int jour) { m_jour = jour; } void Date::asgMois(int mois) m_mois = mois; void Date::asgAnnee(int annee) m_annee = annee; objet dans un état incohérent. asgDate(int jour,int mois,int annee); préférable!  contrôle des changements sur les attributs de la date sans jamais avoir d'état intermédiaire invalide.

Méthode d’assignation : exemple class Date { public: void asgDate(int j, int m, int a); private: int m_jour; int m_mois; int m_annee; }; void Date::asgDate(int j, int m, int a) { m_jour = j; m_mois = m; m_annee = a; } On pourra vérifier la validité du format des données

Méthode de comparaison Accès Assignation Méthode de comparaison Implantation d'un nouveau type Nécessité de pouvoir comparer celui-ci par rapport à un objet du même type. Exemple : une Date comparée à une autre Date: Est-elle égale ? Est-elle inférieure ? Ce type de méthode retourne un booléen.

Méthode de comparaison class Date { public: bool estEgal(const Date& d) const; private: int m_jour; int m_mois; int m_annee; }; bool Date::estEgal(const Date& d) const { return m_jour == d.m_jour && m_mois == d.m_mois && m_annee == d.m_annee; } Évaluation de l'égalité sur la base de la valeur des attributs de l'objet courant par rapport à l'objet passé en paramètre. void main() { Date d1(4,9,2002); Date d2; if (d2.estEgal(d1)) … }

Synthèse

Méthodes utilitaires Rappel: en général, toutes les méthodes publiques Accès Assignation Comparaison Méthodes utilitaires Rappel: en général, toutes les méthodes publiques tous les attributs privés. Méthodes utilitaires : à l’intérieur de la classe sans pour autant vouloir en faire un service publique. sont appelées par les autres méthodes de la classe.

Méthode utilitaire : exemple class Date { public: ... std::string reqDateFormatee() const; private: std::string reqNomMois() const; }; Date d(2,5,1994); cout << d.reqDateFormatee() << endl; Résultat : 2 mai 1994 std::string Date::reqDateFormatee () const { ostringstream os; os << reqJour() << " " << reqNomMois() << " " << reqAnnee(); return os.str(); } Méthode utilitaire utilisée à l'intérieur de la classe std::string Date::reqNomMois () const { static char* NomMois[] = {"janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre","novembre", "décembre"}; return NomMois[reqMois()]; }

Accès Assignation Comparaison Utilitaires Méthodes statiques Méthode de classe ne nécessitant pas la présence d'un objet pour le traitement méthode statique. Comme une fonction mais associée à la classe. Ne touche pas aux attributs de la classe, à moins que ceux-ci ne soient aussi statiques (attribut commun à tous les objets de la classe).

Méthodes statiques : exemple Pas de const pour une méthode statique --- INTERFACE --- class Date { public: void asgDate (int jour, int mois, int annee); static bool valideDate (int jour, int mois, int annee); static bool estBissextile (int annee); private: … }; --- IMPLÉMENTATION --- int Date::jourParMois[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; bool Date::valideDate(int jour, int mois, int annee) { return jour > 0 && mois > 0 && mois <= 12 && ((mois == 2 && jour == 29 && Date::estBissextile(annee)) || (j < jourParMois[mois - 1])); } bool Date::estBissextile(int annee) return (((annee % 4 == 0) && (annee % 100 != 0)) || ((annee % 4 == 0) && (annee % 100 == 0) && (annee % 400 == 0)) ); La méthode peut être déclarée Statique puisque aucun attribut non statique n'est utilisé

N'a pas besoin d'un objet du type de la classe pour être appelée. Méthodes statiques N'a pas besoin d'un objet du type de la classe pour être appelée. Norme : Toujours appeler les méthodes statiques avec le «scope» de la classe et ce, même si vous avez un objet de ce type entre les mains. void main() { if (Date::valideDate(30,2,1999)) … if (Date::estBissextile(2000)) }

Méthode et attribut statiques : exemple class Etudiant { public: Etudiant () {m_nbInstances++;} ~Etudiant () {m_nbInstances--;} static int reqNbInstances () {return m_nbInstances;} private: static int m_nbInstances; }; int Etudiant::m_nbInstances=0; void main() Etudiant et1, et2, et3; cout << "Résultat :" << endl; cout << Etudiant::reqNbInstances() << endl; Etudiant et4, et5; } On peut utiliser un attribut statique dans un objet Une méthode statique ne peut qu'utiliser des attributs statiques. Attribut commun à tous les objets de la classe Résultat: 3 5 On sort du "scope": appel au destructeur

Méthodes optimisées Accès aux attributs : Assignation Comparaison Utilitaires Statiques Méthodes optimisées Accès aux attributs : toujours passer par des méthodes. Méthodes qui transmettent simplement la valeur d’un attribut ... Pénalisant! Faire un appel de fonction veut dire: mettre sur la pile d’appel l’adresse de retour ainsi que les paramètres d’appel. branchement vers le code exécutable de la fonction. Retour : dépiler l’adresse de retour récupérer les résultats...

Méthodes optimisées Solution en C++ pour les méthodes simples: les déclarer inline. = Le compilateur élimine l’appel de fonction en le remplaçant par un accès direct à la donnée. Le code de la méthode doit être très simple et ne pas avoir d’effet de bord. Les méthodes inline font croître rapidement la dimension du code exécutable...

Méthodes optimisées : exemple class Date { public: void asgDate(int jour,int mois,int annee); int reqMois() const; }; inline int Date::reqMois() const return m_mois; } Date.h Méthode inline Méthode non inline #include "Date.h" void Date::asgDate(int jour, int mois, int annee) { m_jour = jour; m_mois = mois; m_annee = annee; } Date.cpp

Fonction inline ou macro? Les programmeurs en C font souvent usage du préprocesseur avec #define pour implanter un fonction inline : #define carre(x) (x)*(x); int x = 5; int y = carre(++x); Résultat : 49 !??! inline int carre(int x) {return x*x;} int x = 5; int y = carre(++x); Résultat : 36.

Fonction inline ou macro L'usage de remplacement de symboles avec #define est source d'erreur, notamment pour les fonctions mathématiques. En C++, utiliser les fonctions ou les méthodes inline à la place. Les méthodes inline assurent la protection des données (encapsulation) assurent la validation de type d'une fonction régulière. améliorent la performance en évitant les appels de fonction.

Synthèse

Département d'informatique - Université Laval 2. Concepts orientés objets 2.1 Introduction 2.2 Élément du modèle objet 2.3 La classe 2.4 Méthodes par catégorie Département d'informatique - Université Laval 2.5 Implantation avancée

Implantation avancée Problème de collision de noms Entrées/sorties Le passage de paramètres Surcharge de méthode

Problème de collision de noms… Qu’arrive-t-il si 2 fonctions globales différentes ont le même prototype ? // MaLib2.h int f(); class A{}; // MaLib1.h int f(); #include "MaLib1.h" #include "MaLib2.h" int g(){ return 5 + f(); //Quel f() ? }

Solution : créer de namespaces regroupement logique de fonctions, de classes, etc. Possibilité de lui donner un nom. - NomDuNamespace::NomDeLEntite Pas d'ambiguïté

exemple // MaLib1.h // MaLib2.h namespace Util{ namespace Tp1{ int f(); } // MaLib2.h namespace Tp1{ int f(); class A{}; } #include "MaLib1.h" #include "MaLib2.h" int g(){ Tp1::A a; return 5 + Util::f(); // Ah, ok } On se sert de l'opérateur d'appartenance ::

using namespace namespace directement accessible : commande using 22/04/2017 using namespace namespace directement accessible : commande using #include "MaLib1.h" #include "MaLib2.h" using namespace Tp1; int h(){ A a; int x = f(); return x + Util::f(); } Par le using, c'est Tp1::f(). H2007

Bon usage du using Inutile de mettre des using pour chacun des namespaces disponibles : l'ambiguïté revient. Un using peut-être local : Ne jamais utiliser de using dans un .h : tous les fichiers qui l'incluront seront pollués. // Quelque part { using namespace Util; // Util est accessible directement dans ce bloc }

Namespace et librairie standard librairie standard en C++ : dans le namespace std : Fonctions I/O ( console, fichiers, ... ) Classes de base ( string, iterator, ... ) Conteneurs ( vector, list, ... ) Algorithmes standardisés ( tri, recherche, …) souvent la commande using namespace std; dans les fichiers .cpp .

Exemple d'interface : Bidon.h #include "MaLib1.h" #include "MaLib2.h" #include <string> namespace util { class B public : std::string afficher(); private: Tp1::A a; std::string tmp; }; } // --- namespace util std::string afficher() using namespace std; string s; // traitement à faire return s; } On peut rajouter quelque chose dans un namespace déjà défini ailleurs. Ce using n'affecte que le corps de cette fonction.

Entrées et sorties : La famille des iostream Collision de noms Entrées et sorties : La famille des iostream Une stream en C++ : séquence de caractères permettant de faire les opérations d'entrées/sorties. Une ostream gère les sorties inclut la définition de l'opérateur <<. Une istream gère les entrées inclut la définition de l'opérateur >>. ios iostream istream ostream

ostream, istream : streams principales Une ostream peut être redirigée vers : l'écran (cout), la console d'erreur (cerr), le fichier d'historique (clog), un fichier (ofstream), un espace en mémoire (ostringstream, ostrstream). Une istream peut être redirigée vers : le clavier (cin), un fichier (ifstream), un espace en mémoire (istrstream). Plus de détails à venir.

Entrées et sorties cout << "Bonjour"; //Affiche Bonjour Envoi et réception des informations de la console via des flux d'entrée et de sortie: input/output stream cout = flux de sortie pour l'affichage dans la console "console output" L'opérateur << envoi de l'information dans cout, donc vers la console. cout << "Bonjour"; //Affiche Bonjour

Entrées et sorties : cout Enchaînement de plusieurs << dans une même instruction. Peut prendre tous les types de base en C++. Pas besoin de spécifier le format comme avec un printf. Un retour de chariot ( '\n' ) string nom = "Toto"; int age = 10; cout << "Bonjour " << nom << endl; cout << "Tu as " << age << " ans.";

Entrées et sorties : cin = flux d'entrée de la console ce que tape l'utilisateur console input L'opérateur >> ( attention au sens ) reçoit l'information de cin, donc du clavier. cout << "Entrez votre nom : " ; string nom; cin >> nom; cout << "Entrez votre poids : " ; double poids; cin >> poids;

Entrées et sorties : cin Quelques contraintes pour la saisie d'information: >> prend comme délimiteurs pour un string : espace, tab, RC Pour lire une chaîne de caractères comprenant des espaces ou des "tab" : string nomCompose; char buffer[256]; cin.getline(buffer, 255); nomCompose = buffer;

Entrées et sorties : cin cin >> poids; ne "consomme pas" les délimiteurs cin.getline(buffer, 255); oui Solution: double poids; cin >> poids; int nombre; cin >> nombre; cin.ignore();//consomme le délimiteur qui est resté // dans le flux cin.getline(buffer, 255);//pas besoin de ignore // ici, getline consomme tout

Entrées et sorties cin/cout définis dans <iostream> inclure l'entête cin/cout, les opérateurs << et >> et la classe string définis dans le namespace std. Dans un .cpp : ajouter au début du fichier using namespace std; Dans un .h : évitez le using, utilisez plutôt explicitement le nom du namespace avec ::

Entrées et sorties : exemple #include <iostream> #include <string> using namespace std; void main() { cout << "Entrez votre nom : " ; string nom; cin >> nom; cout << "Entrez votre poids (Kg): " ; double poids; cin >> poids; cout << "Bonjour : " << nom << endl; cout << "Votre poids est " << poids << "kilo" << endl; } Problème si des espaces. Utilise plutôt un buffer et méthodes de cin.

I/O avec des fichiers Fichier : séquence d’octets terminée par une « marque de fin de fichier » (EOF). En C++ : vus comme des flux d’octets ou de caractères. ofstream : Pour l’écriture dans un fichier. ifstream : Pour la lecture à partir d’un fichier. Deux types de lecture/écriture : Mode texte : Peut être lu comme un document texte, caractère par caractère, mot par mot, ligne par ligne, etc. Mode binaire : décoder les informations, octet par octet. Se trouve dans l’entête <fstream>

Écriture en mode texte Pour ouvrir un fichier en écriture : déclarer un objet de type ofstream : 1er argument : le chemin et le nom du fichier. 2e argument : le type d’ouverture ios::out : Efface tout le contenu, si le fichier existait déjà. ios::app : Écrit après ce qu’il y a déjà dans le fichier. Si le fichier n’existe pas, il est créé dans les deux cas. On peut aussi déclarer un ofstream sans ouvrir le fichier. Pour ouvrir le fichier plus tard, utilisez la méthode open ofstream ofs("FichierAEcrire.dat",ios::out); ofstream ofs; // ... ofs.open("FichierAEcrire.dat",ios::app);

Pourra être relue comme une ligne entière Exemple : //Ouverture d'un fichier en écriture ofstream ofs ("Moto.dat",ios::out); if (!ofs) { cerr << "Ouverture impossible" <<endl; return 1; } ofs << 2 << endl; // nombre de motos ofs << "Honda Shadow" << endl; ofs << 1986 <<endl; ofs << "Honda Valkyrie Rune" << endl; ofs << 2004 << endl; // Pour forcer la fermeture ofs.close(); Si le fichier ne peut être ouvert ( mauvais chemin ou déjà ouvert ), l’opérateur ! renvoie faux. Pourra être relue comme une ligne entière 2 Honda Shadow 1986 Honda Valkyrie Rune 2004

Lecture en mode texte Déclarer un objet de type ifstream ios::in : lecture en mode texte, sans modification. ifstream ifs("FichierALire.dat", ios::in);

Exemple : Modèle : Honda Shadow Annee : 1986 { ifstream ifs("Moto.dat",ios::in); if(!ifs) cerr << "Ouverture impossible" <<endl; return 1; } char ligne[256]; int nbMotos; ifs >> nbMotos; ifs.ignore(100, '\n'); for (int i=0; i<nbMotos; i++) ifs.getline(ligne,255); cout << " Modele : " << ligne << endl; ifs >> annee; cout << " Annee : " << annee << endl << endl; } // destructeur de ifs appelé, qui ferme le fichier Modèle : Honda Shadow Annee : 1986 Modèle : Honda Valkyrie Rune Annee :2004

Le passage de paramètre Collision de noms Entrées/sorties Le passage de paramètre Types de passage de paramètres en C++ ? trois types : le passage par valeur, le passage par pointeur, le passage par référence (nouveauté par rapport au C). Quand utiliser chacun de ces types?

Coût de la copie lorsqu'on passe par valeur. Le passage par valeur Permet de passer des valeurs sans que la fonction appelée puisse modifier celles-ci. pas d'«effet de bord» Les modifications sur les données passées n'ont pas d'influence sur les données originales. Coût de la copie lorsqu'on passe par valeur.

Le passage par valeur : Exemple #include <iostream> #include <string> using namespace std; string MettreEnMajuscule (string texte) { unsigned int dim = texte.size(); for (int i=0; i<dim; i++) { texte[i] = (char)toupper(texte[i]); } return texte; } void main() { string nom = "programmation"; string NOM = MettreEnMajuscule(nom); cout << "Minuscule : " << nom << endl; cout << "Majuscule : " << NOM << endl; } Résultat: Minuscule : programmation Majuscule : PROGRAMMATION

Le passage par pointeur Avec le langage C, Pour éviter le coût de la copie on passait les paramètres par pointeur. Approprié lorsque l'on veut que les données soient modifiées. Mais lorsqu'on ne veut pas …?!

Le passage par pointeur : Exemple Passage par pointeur : Accès direct aux données originales #include <iostream> #include <string> using namespace std; string MettreEnMajuscule (string* texteP) { unsigned int dim = texteP->size(); for (int i=0; i<dim; i++) { (*texteP)[i] = (char)toupper((*texteP)[i]); } return *texteP; } void main() { string nom = "programmation"; string NOM = MettreEnMajuscule(&nom); cout << "Minuscule : " << nom << endl; cout << "Majuscule : " << NOM << endl; } Résultat: Minuscule : PROGRAMMATION Majuscule : PROGRAMMATION

Le passage par référence Le passage par référence, tout comme le passage par pointeur, donne directement accès aux données originales. Pas de coût associé au passage par référence mais il y a risque de corruption des données par les fonctions appelées.

Le passage par référence : exemple Passage par référence : Accès direct aux données originales #include <iostream> #include <string> using namespace std; string MettreEnMajuscule (string& texte) { unsigned int dim = texte.size(); for (int i=0; i<dim; i++) { texte[i] = (char)toupper(texte[i]); } return texte; } void main() { string nom = "programmation"; string NOM = MettreEnMajuscule(nom); cout << "Minuscule : " << nom << endl; cout << "Majuscule : " << NOM << endl; } Résultat: Minuscule : PROGRAMMATION Majuscule : PROGRAMMATION

Le passage par référence constante Le langage C++ offre la possibilité de protéger les données originales en utilisant le passage par référence ET le mot const. Il n'y a plus de coût associé à la copie des données et il n'y a plus de risque de modification des données originales. Le passage par référence constante donne le même résultat que le passage par valeur, la copie en moins !

Le passage par référence constante : exemple Passage par référence constante : Accès direct aux données originales sans pouvoir les modifier. #include <iostream> #include <string> using namespace std; string MettreEnMajuscule (const string& texte) { unsigned int dim = texte.size(); for (int i=0; i<dim; i++) { texte[i] = (char)toupper(texte[i]); } return texte; } void main() { string nom = "programmation"; string NOM = MettreEnMajuscule(nom); cout << "Minuscule : " << nom << endl; cout << "Majuscule : " << NOM << endl; } Résultat: Minuscule : programmation Majuscule : PROGRAMMATION

Conclusion Ne jamais utiliser le passage par valeur sauf pour les types de base du langage. Toujours utiliser le passage par référence constante si on désire que les données originales ne soient pas modifiées. Toujours utiliser le passage par référence si on désire que les données originales soient modifiées. Le passage par pointeur pourra être utilisé dans quelques rares cas, notamment pour le polymorphisme. (Nous y reviendrons)

Collision de noms Entrées/sorties Passage de paramètres Surcharge de méthode Les langages orientés objet permettent une première forme de polymorphisme: la surcharge de méthode (ou de fonction). Il est permis de créer plusieurs méthodes du même nom dans la classe pourvu qu'elles varient au niveau des paramètres. Lorsqu'une méthode surchargée est appelée, le compilateur sélectionne la bonne selon les paramètres: nombre, type, ordre. La surcharge doit être utilisée pour implanter des traitements similaires.

Surcharge de méthode (2) Prenons un exemple d'une string: Le compilateur sélectionne la bonne méthode en fonction du type en paramètre. class string { public: (…) int rechercher (char c) const; int rechercher (const char* sP) const; int rechercher (const string& s) const; };

Surcharge de méthode (3) Attention: le compilateur utilise seulement la liste des paramètres pour distinguer les fonctions de même nom. Le type de retour n'est pas pris en compte. class Quelconque { public: (…) bool methode1 (int p1, int p2); double methode1 (int p1, int p2); }; Pour le compilateur, ces deux méthodes sont identiques.

Paramètre par défaut (1) Parfois, certaines méthodes ont besoins de plusieurs paramètres pour correctement faire le travail. Toutefois pour les cas simples ou les plus fréquents, ces paramètres supplémentaires sont toujours les mêmes. Il est possible d'utiliser la technique des paramètres par défaut.

Paramètre par défaut (2) Soit une fonction qui permet d'imprimer un entier dans n'importe quelle base : 2, 10, 16… La plupart du temps se sera en base 10. void imprimer (int valeur, int base = 10); void main() { imprimer (31); imprimer (31, 10); imprimer (31, 16); imprimer (31, 2); } Résultat : 31 31 1F 11111

Paramètre par défaut (3) Une autre implantation aurait pu utiliser la surcharge de fonction à la place : void imprimer (int valeur, int base); inline void imprimer (int valeur) { imprimer(valeur, 10); } void main() imprimer (31); imprimer (31, 10); imprimer (31, 16); imprimer (31, 2); Résultat : 31 31 1F 11111

Paramètre par défaut (4) Les paramètres par défaut sont vérifiés à la compilation et évalués à l'exécution. Les paramètres par défaut doivent être fournis à partir des derniers arguments seulement. Correct : int foo(int a, int b=0, char* strP=0); Incorrect : int goo(int a=0, int b=0, char* strP); int hoo(int a=0, int b, char* strP=0);

Surcharge de méthode et paramètre par défaut l'utilisation de la surcharge de méthode peut entrer en conflit avec l'utilisation des paramètres par défaut… class A { public: A(); A(const A& obj); A(int v1=0, int v2=0);   private: int m_v1; int m_v2; }; Que peut-on dire à propos de ces constructeurs ? Il y aura conflit entre A() et A(int v1=0, int v2=0).

Questions En quoi se comparent deux méthodes surchargées? Quel conflit peut survenir entre la surcharge de méthode et les paramètres par défaut?