introduction à c++

382
Introduction à la programmation objet et générique avec C++ 1 Introduction à la programmation objet et générique en C++ Christophe Vaudry mél : [email protected] blog : thegeekintheshell.blogspot.com site Web : cvaudry.developpez.com

Upload: christophe-vaudry

Post on 22-May-2015

3.785 views

Category:

Technology


0 download

DESCRIPTION

Cours d'introduction à C++ pour un public connaissant le langage C et ayant des bases en algorithmique, mais n'ayant pas de connaissance particulière sur les objets

TRANSCRIPT

Page 1: Introduction à C++

Introduction à la programmation objet et générique avec C++ 1

Introduction à la programmation objet et générique en C++

Christophe Vaudrymél : [email protected]

blog : thegeekintheshell.blogspot.comsite Web : cvaudry.developpez.com

Page 2: Introduction à C++

Introduction à la programmation objet et générique avec C++ 2

Présentation généralePrésentation générale✔ Introduction aux « concepts objet » et à la programmation

Objet– Connaître les principaux concepts « objet »– Savoir les appliquer pour concevoir des programmes

• Notamment savoir appliquer ces concepts en C++✔ Introduction au langage C++

– Acquerir un savoir faire en programmation C++ en général et plus particulièrement en

• Programmation orientée objet en C++• Programmation générique en C++

– De manière plus générale être capable • de lire et de comprendre un programme C++• de poursuivre le développement d'un programme C++

commencé par un autre• De savoir programmer une application complète en C++

✔ Audience originelle– Ce cours a été dispensé en première année de l'ISAIP Dijon

de 2004 à 2006.

Page 3: Introduction à C++

Introduction à la programmation objet et générique avec C++ 3

Une vue d'ensemble de C++

Page 4: Introduction à C++

Introduction à la programmation objet et générique avec C++ 4

Plan général du coursPlan général du cours✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques (Livres et Web)– Les outils utilisés dans ce cours

✔ Introduction aux concepts de la programmation orientée objet– Conception et « Orienté Objet »– Les cartes CRC

✔ Introduction au C++– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

✔ Notes :– Les flots d'entrées/sorties et la bibliothèque standard « STL »

ne sont pas abordés dans ces transparents : ces thématiques ont été abordées lors de TP associés à ce cours.

Page 5: Introduction à C++

Introduction à la programmation objet et générique avec C++ 5

Une vue d'ensemble du C++ : sommaireUne vue d'ensemble du C++ : sommaire✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques

• Livres• Web

– Les outils utilisés dans ce cours

Page 6: Introduction à C++

Introduction à la programmation objet et générique avec C++ 6

historique (1)historique (1)✔ Petit historique du C++

– Le C++ a été conçu aux laboratoires Bell chez AT&T (comme le C) par Bjarne Stroustrup à la fin des années 70 / début des années 80

– Le C++ tel que nous le connaissons actuellement reprend des idées et des concepts de différents langages.

• Le C++ a été conçu comme une extension du C– C peut-être considéré comme un sous-ensemble de

C++– les facilités de bas niveau offertes par le C pour traiter

la plupart des tâches systèmes ont été conservées en C++

• Les concepts de classe, de classe dérivée et de fonction virtuelle viennent de Simula67

• La surcharge des opérateurs vient d'Algol68• Les patrons (« template ») sont inspirés d'Ada et de Clu• Le mécanisme de gestionsdes exceptions est inspiré de

ceux d'Ada, Clu et ML.

Page 7: Introduction à C++

Introduction à la programmation objet et générique avec C++ 7

historique (2)historique (2)✔ Petit historique du C++

C++

CluC

Ada ML

Algol

Pascal

Simula

Java

Page 8: Introduction à C++

Introduction à la programmation objet et générique avec C++ 8

historique (3)historique (3)✔ Petit historique du C++

– Pourquoi le nom est-il « C++ » ?• Explication « historique » :

– Le premier « + » : « C with classes » en 1979• C with classes = C + {classes, heritage, fonctions

amies, constructeurs, destructeurs, fonctions inline , ...)

– Le deuxième + : • C++ = C with classes + {references, surcharge,

liaison dynamique, héritage multiple, patrons• Autre explication

– C++ : peut-être lu comme « 1 de plus que C », successeur de C (« jeu de mots » sur l'opérateur ++)

– Ce nom aurait été inventé par Rick Masciti en 1983

Page 9: Introduction à C++

Introduction à la programmation objet et générique avec C++ 9

historique (4)historique (4)✔ Petit historique du C++

– Le C++ est standardisé : ISO/IEC Final Draft International Standard 14882

• Standard défini par le Comité ANSI X3J16 et le groupe de travail ISO WG-21.

– X3 a été récemment renommé/remplacé par The INCITS — the InterNational Committee for Information Technology Standards

– La page du INCITS Technical Committee pour le C++ est http://www.incits.org/tc_home/j16.htm

Page 10: Introduction à C++

Introduction à la programmation objet et générique avec C++ 10

historique (5)historique (5)✔ Quelques mots sur le créateur du C++, Bjarne Stroustrup

– Bjarne Stroustrup est toujours en activité :-)• Vous pouvez consulter sa page à l'URL :

– http://www.research.att.com/~bs/• Sur ses pages vous trouverez des articles, des FAQ et

différentes ressources liées au C++... une adresse à conserver donc.

Page 11: Introduction à C++

Introduction à la programmation objet et générique avec C++ 11

Objectifs de conception du C++ (1)Objectifs de conception du C++ (1)✔ Présentation du C++ par Bjarne Stroustrup en quelques mots

– «  C++ is a statically-typed general purpose language relying on classes and virtual functions to support object-oriented programming, templates to support generic programming and providing low-level facilities to support detailed systems programming »

– Le C++ a été conçu pour rendre la création de bons programmes plus facile et plus plaisante au programmeur, mais sans sacrifier l'efficacité du code généré.

✔ Pourquoi prendre comme base le langage C ?– Bjarne Stroustrup a choisi le langage C comme langage de

base pour C++ car• C est souple, succint et de relativement bas niveau• C est adapté à la majorité de tâches de bas niveau• C est très largement disponible sur la majorité des

plateformes et des OS• Il est partie intégrante des environnements UNIX

Page 12: Introduction à C++

Introduction à la programmation objet et générique avec C++ 12

Objectifs de conception du C++ (2)Objectifs de conception du C++ (2)✔ Un langage généraliste et « multi-paradigmatique »

– Le C++ est par nature un langage dit « multi-paradigmatique »• C'est-à-dire qu'il a été conçu pour faciliter l'utilisation de

plusieurs styles de programmation différents– Programmation Bas-niveau– Programmation Orientée Objet– Programmation Générique

– Le C++ est un langage généraliste• Il n'est pas conçu spécifiquement pour programmer un

type d'applications particulières (I.A., réseaux, etc.) ou pour un domaine particulier (info. de gestion, scientifique, etc.)

• Un peu orienté quand même vers la programmation système

– Le C++ a été concçu pour supporter les abstractions de données et la programmation par objets en plus des techniques de programmation C traditionnelles.

Page 13: Introduction à C++

Introduction à la programmation objet et générique avec C++ 13

Présentation d'ensemble du C++ (1)Présentation d'ensemble du C++ (1)✔ C++ est un langage de programmation statiquement typé

– Les types sont vérifiés au moment de la compilation par opposition avec le typage dynamique dans lequel les types sont donnés et vérifiés au moment de l'exécution.

• La plupart des règles du langage sont vérifiés par le compilateur avant que le programme ne commence sont exécution

• Chaque entité du programme a un type et doit être utilisée en accord avec les contraintes imposée par ce type.

• La compilateur détecte les mauvaise utilisations de types et s'assure que les conversions définie par le langage ou par l'utilisateur soient effectuées.

– Une des puissances du C++ est de laisser beaucoup de latitude à l'utilisateur pour définir quelles opérations et quelles conversions sont acceptables pourr un type utilisateur.

Page 14: Introduction à C++

Introduction à la programmation objet et générique avec C++ 14

Présentation d'ensemble du C++(2)Présentation d'ensemble du C++(2)✔ Les styles de programmation supportés par le C++

– Le C++ propose des facilités pour• Une programmation bas niveau efficace

– Modèle de la mémoire proche de la machine identique à celle du C

• On retrouve bien sûr la notion de pointeur– Héritage du C pour les notions de fonctions,

d'expressions et de structure de contrôle• L'abstraction de données

– Existence de mécanisme pour définir et utiliser efficacement de types de données utilisateurs

• La programmation orientée objet– Notion de classe, de classes abstraites, d'héritage et

de hiérarchie de classes et de fonctions virtuelles• La programmation générique

– Notion de patron de classe (« template »).

Page 15: Introduction à C++

Introduction à la programmation objet et générique avec C++ 15

Présentation d'ensemble du C++(3)Présentation d'ensemble du C++(3)✔ Une distinction importante à faire

– Un langage « supporte » un style de programmation s'il fournit les facilités qui le rendent pratique (i.e. raisonnablement facile, sûr et efficace) dans l'utilisation de ce style.

• Un langage ne supporte pas un style s'il demande un effort exceptionnel ou une certaine habilité pour écrire programme respectant ce style.

Page 16: Introduction à C++

Introduction à la programmation objet et générique avec C++ 16

Présentation d'ensemble du C++ (4)Présentation d'ensemble du C++ (4)✔ Le style de programmation bas niveau : « un meilleur C » (1)

– En C, un tableau est simplement une séquence d'emplacements en mémoire et un pointeur est une variable qui contient l'adresse d'un emplacement mémoire

• En C++, la notion de mémoire est identique à celle du C– La philosophie de la gestion de la mémoire en C/C++

• « C programmers think memory management is too important to be left to the computer. Lisp programmers think memory management is too important to be left to the user. »

Page 17: Introduction à C++

Introduction à la programmation objet et générique avec C++ 17

Présentation d'ensemble du C++ (5)Présentation d'ensemble du C++ (5)✔ Le style de programmation bas niveau : « un meilleur C » (2)

– En C et en C++, il y a 3 manières fondamentales d'utiliser la mémoire

• On a la mémoire dite « statique » (static memory)– C'est une entité dont l'emplacement mémoire est

alloué par le « linker » pour la durée du programme• Les variables globales, les membres de classes

statiques, les variables définies « statiques » dans les fonctions

– Une entité allouée en mémoire statique est construite une fois et persistent jusqu'à la fin du programme.

• Son adresse ne change pas pendant toute la durée d'exécution du programme

– Les entités « statiques » peuvent poser des problèmes dans des programmes multithreadés.

Page 18: Introduction à C++

Introduction à la programmation objet et générique avec C++ 18

Présentation d'ensemble du C++ (6)Présentation d'ensemble du C++ (6)✔ Le style de programmation bas niveau : « un meilleur C » (3)

– En C et en C++, il y a 3 manières fondamentales d'utiliser la mémoire

• On a la mémoire dite « statique » (static memory)• On a la mémoire dite « automatique » (automatic memory)

– Utilisée pour les arguments de fonctions et les variables locales (par défaut) pour les types primitifs

– Ce type de mémoire est gérée automatiquement• création et destruction automatique quand on

rentre dans la fonction ou le bloc concerné.– Utilisation de la pile en général

• On a la mémoire allouée dynamiquement– Utilisée pour les objets, lors d'une requête explicite du

programme. Cette mémoire est restituée de même par demande explicite du programme

– On utilise le tas (« heap »)

Page 19: Introduction à C++

Introduction à la programmation objet et générique avec C++ 19

Présentation d'ensemble du C++ (7)Présentation d'ensemble du C++ (7)✔ L'abstraction de données

– Notion de TAD (Type Abstrait de Données) ou ADT (Abstract Data Type) en anglais.

• C'est un structure de données et un ensemble de fonctions et de procédures pour opérer sur cette structure de données

• Par exemple la Pile est un TAD– Le programmeur a besoin de mécanismes pour pouvoir créer

facilement des nouveaux types de données qui seront plus appropriées pour le domaine d'application pour lequel il conçoit son programme

– En C++, le terme pour les type utilisateur est « classe » • En C++, chaque nouvelle classe créée correspond à un

nouveau type de données.• On pourra également redéfinir en C++ les opérateurs (+, =,

[], <<, >>, etc.) pour ces nouveaux types définis créés.

Page 20: Introduction à C++

Introduction à la programmation objet et générique avec C++ 20

Présentation d'ensemble du C++ (8)Présentation d'ensemble du C++ (8)✔ La Programmation Orientée Objet

– On peut considérer que la POO est un ensemble de techniques qui se basent sur des hiérarchies de classes pour fournir extensibilité et flexibilité.

– En C++ les principaux dispositifs orientées objets du langage sont la capacité pour l'utilisateur de définir des nouveaux types en créant des classes, de dérivées ces classes les unes des autres et la notion de fonction virtuelle

Page 21: Introduction à C++

Introduction à la programmation objet et générique avec C++ 21

Présentation d'ensemble du C++ (8)Présentation d'ensemble du C++ (8)✔ La Programmation Générique

– Le C++ propose la paramétrisation de classe par un type avec la notion de patron (« template »).

– Dans la bibliothèque standard du C++, on retrouve la fameuse STL (Standard Template Library) qui utilise les patrons pour fournir des « conteneurs » (liste, pile, etc.) et des algorithmes (tris, etc.).

• La bibliothèque standard du C++, reprend également l'intégralité de la bibliothèque standard du C.

• On aura également en C++ de nouveaux outils pour gérer les entrées/sorties.

Page 22: Introduction à C++

Introduction à la programmation objet et générique avec C++ 22

Présentation d'ensemble du C++ (9)Présentation d'ensemble du C++ (9)✔ Autres caractéristiques facilitant les « gros » développement

– Notion d'exceptions• Les exceptions sont utilisées pour transférer le contrôle de

l'endroit auquel l'erreur se produit à un autre endroit du programme dans lequel on souhaite centraliser la gestion de ce type d'erreur.

– Notion d'espace de noms (« namespaces »)• Un espace de nom délimite un espace dans lequel des

noms vont être connus– Les espaces de noms sont utilisés pour grouper des

un ensemble de déclarations en rapport et maintenir des éléments séparées clairement séparées.

• Les espaces de noms fournissent un outil intéressant pour la gestion de différentes bibliothèques et de différentes versions de code.

Page 23: Introduction à C++

Introduction à la programmation objet et générique avec C++ 23

Références bibliographiques (1)Références bibliographiques (1)✔ Bibliographie

– « Le Langage C++ » (Edition revue et corrigée) de Bjarne Stroustrup chez Pearson Education

– « C++ - Précis et Concis » de Kyle Loundon chez O'Reilly– « STL - Précis et Concis » de Ray Lischner chez O'Reilly– « C – Précis et Concis » de Peter Prinz et Ulla Kirch-Prinz– « Algorithmes en C++ », 3ème édition, de Robert Sedgewick,

Christopher Van Wyk, Jean-Luc Bourdon, Philippe Laroque, chez Pearson Education.

– Voir également pour des références plus théoriques sur les langages à objets

• « Les Langages à Objets » de Gerald Masini, Amedeo Napoli, Dominique Colnet, Daniel Léonard et Karl Tombre, chez InterEditions

Page 24: Introduction à C++

Introduction à la programmation objet et générique avec C++ 24

Références bibliographiques (2)Références bibliographiques (2)✔ Webographie (1)

– Le site de Bjarne Stroustrup : • http://www.research.att.com/~bs/

– Les informaticiens ont de l'humour : une fausse interview de Bjarne Stroustrup :

• http://www-users.cs.york.ac.uk/~susan/joke/cpp.htm– Voir également la vraie interview de Bjarne Stroustrup :

• http://www.research.att.com/~bs/ieee_interview.html– FAQ sur le C++ :

• http://www.parashift.com/c++-faq-lite/– Le cours très complet de Christian Casteyde

• http://casteyde.christian.free.fr/online/cours_cpp/book1.html– Listes de liens relatives au C++ sur le site de Bloodshed Dev

• http://www.bloodshed.net/c/index.html – Un site en anglais très complet, avec notamment une

présentation de la bibliothéque standard• http://www.cplusplus.com/

Page 25: Introduction à C++

Introduction à la programmation objet et générique avec C++ 25

Références bibliographiques (3)Références bibliographiques (3)✔ Webographie (2)

– Sites de ressources en lignes pour les programmeurs C/C++• http://www.cprogramming.com/• Voir notamment

– http://www.cprogramming.com/begin.html– http://www.cprogramming.com/tutorial.html

• Voir également leurs forums– http://cboard.cprogramming.com/

– Un livre en anglais plutôt bien fait sur la programmation orientée objet (en général)

• http://web.engr.oregonstate.edu/~budd/Books/oopintro3e/info/ReadMe.html– Ressources en ligne du « Open Book Project »

• http://www.ibiblio.org/obp/– Autres ressources utiles

• http://cplus.about.com/• http://www.robertjacobs.fsnet.co.uk/index.htm

Page 26: Introduction à C++

Introduction à la programmation objet et générique avec C++ 26

Les outils utilisés dans ce coursLes outils utilisés dans ce cours✔ CodeBlocks

– Ce cours s'appuie pour la partie pratique sur l'IDE CodeBlocks et le compilateur MinGW (http://www.mingw.org/) sous Windows.

• Une version Linux existe également– http://www.codeblocks.org/

✔ GTK + (binding GTKmm pour C++) et Glade– Bibliothèque d'interface graphique fonctionnant sous Windows

et Linux.• http://www.gtk.org/• http://www.gtkmm.org/

– Glade est un constructuer d'interface• http://glade.gnome.org/

Page 27: Introduction à C++

Introduction à la programmation objet et générique avec C++ 27

Autres outils C/C++ (1)Autres outils C/C++ (1)✔ Disponibilité des outils

– Les outils cités ci-après sont disponibles sur Everest, dans le partage Donnees et le répertoire \Logiciels\Developpement

✔ Dev C++– Ce cours s'appuie pour la partie pratique sur l'IDE DevC++ et

le compilateur MinGW sous Windows.• Si vous pouvez l'utiliser, c'est l'IDE que nous vous

conseillons d'utiliser pour les Tps• Une version Linux ne devrait pas tarder à sortir• http://www.bloodshed.net/devcpp.html

– Un tutoriel sur DevC++• http://www.geocities.com/uniqueness_template/

– Pour avoir de l'aide sur Dev C++• http://www.bloodshed.net/dev/help.html

– Les DevPacks Repository• http://devpaks.org/• Ce sont des bibilothèques dans un format adapté à Dev

C++ et MinGW, rendant leur gestion facile depuis l'IDE.

Page 28: Introduction à C++

Introduction à la programmation objet et générique avec C++ 28

Autres outils C/C++ (2)Autres outils C/C++ (2)✔ Eclipse et CDT

– Sur le serveur Linux est installé l'IDE Eclipse et CDT (C/C++ Development Toolkit)

• http://www.eclipse.org/ et http://www.eclipse.org/cdt/– Voir également l'article sur le développement en C/C++ avec

Eclipse à l'URL : • http://www-128.ibm.com/developerworks/opensource/library/os-ecc/

✔ MinGW– Si vous utilisez Eclipse sous Windows vous aurez besoin d'un

compilateur C/C++. Nous vous recommandons d'utiliser MingW

• http://www.mingw.org/• http://sourceforge.net/projects/mingw/

– Il peut être intéressant d'installer également MSYS✔ Anjuta

– Sous linux il est également possible d'utiliser Anjuta• http://anjuta.sourceforge.net/

Page 29: Introduction à C++

Introduction à la programmation objet et générique avec C++ 29

Introduction au concept de la POO

Page 30: Introduction à C++

Introduction à la programmation objet et générique avec C++ 30

Introduction aux concepts de la POO Introduction aux concepts de la POO : sommaire: sommaire✔ Introduction aux concepts de la programmation orientée

objet– Conception et « Orienté Objet »– Les cartes CRC

Page 31: Introduction à C++

Introduction à la programmation objet et générique avec C++ 31

Conception et « Orienté Objet » (1)Conception et « Orienté Objet » (1)✔ De l'utilité des langages de programmation

– Un langage de programmation sert à 2 choses• Fournir un moyen au programmeur de spécifier des

actions à exécuter• Fournir un ensemble de concepts utilisés par le

programmeur quand il pense à ce qui peut être fait– Le premier point demande un langage « proche de la

machine »• ainsi tous les aspects importants de la machine sont gérés

simplement et efficacement, d'une manière raisonnablement claire pour le programmeur.

– Le deuxième point demande un langage « proche du problème à résoudre », « proche de la tâche à accomplir »

• ainsi les concepts d'une solution peuvent être exprimés directement et de façon concise.

Page 32: Introduction à C++

Introduction à la programmation objet et générique avec C++ 32

Conception et « Orienté Objet » (2)Conception et « Orienté Objet » (2)✔ Remarques sur l'orienté objet en C++

– Comme nous l'avons déjà indiqué, C++ n'est pas un langage purement objet contrairement à des langages comme Java, SmallTalk ou Ruby par exemple.

• C++ propose en effet des facilités pour programmer « par objets » mais n'oblige pas à programmer « par objets ».

– La « vision objet » que propose C++ repose sur la notion de classe

• Comme Simula, Java ou SmallTalk, C++ est ce qu'on nomme un langage de classe

– C'est un type particulier de « langage à objets », il en existe d'autre

• Par exemple les langages de prototype ou les langages de frames

• Les langages de classes sont certainement, à l’heure actuelle, le type de « langage objet » le plus répandu.

– L'utilisation des classes est un des grands intérêts de C++ par rapport à C.

Page 33: Introduction à C++

Introduction à la programmation objet et générique avec C++ 33

Conception et « Orienté Objet » (3)Conception et « Orienté Objet » (3)✔ Avant d'écrire un programme

– quelque soit le langage dans lequel on l’écrit, on passe par une phase d’analyse

• Il est nécessaire d’analyser le problème que le programme est sensé résoudre ou le besoin auquel il est sensé répondre pour pouvoir le traduire en une solution informatique efficace

– Schématiquement, c’est ce qu’on nomme la conception• Avant de construire un bâtiment, en général on fait un

plan. • Ce n’est pas différent en informatique

– conception du programme (le plan), puis mise en œuvre technique - le codage - dans un langage de programmation.

Page 34: Introduction à C++

Introduction à la programmation objet et générique avec C++ 34

Conception et « Orienté Objet » (4)Conception et « Orienté Objet » (4)✔ Analyser le problème c'est d'abord se poser les bonnes

questions !– C’est comme pour une dissertation de philosophie, il s’agit de

bien comprendre le problème pour ne pas être hors sujet!• Quelles sont les objets qui interviennent dans le

problème? Quelles sont les données, les objets, que le programme va manipuler?

• Quelles vont être les relations entre ces objets? Quelles sont les opérations que je vais pouvoir effectuer sur ces objets?

– Les méthodologies de développement logiciel sont sensées aider à systématiser la recherche de ces bonnes questions.

• Il existe de nombreuses méthodologies différentes avec des manières d’aborder les problèmes différentes

Page 35: Introduction à C++

Introduction à la programmation objet et générique avec C++ 35

Conception et « Orienté Objet » (5)Conception et « Orienté Objet » (5)✔ Quand on analyse le problème, il faut faire preuve

– d’efficacité• quelle méthode me permettra d’obtenir le plus vite, le plus

clairement, le plus simplement possible les résultats attendus.

– de paresse• dans ce que j’ai développé avant, que puis-je réutiliser?

– de prévoyance• comment s’assurer que le programme sera facilement

réutilisable et extensible?

Page 36: Introduction à C++

Introduction à la programmation objet et générique avec C++ 36

Conception et « Orienté Objet » (6)Conception et « Orienté Objet » (6)✔ Vers les langages à objets (1)

– Nécessité de faciliter cette analyse et surtout sa transcription la plus directe possible en un programme

– Au début de l’informatique, les langages étaient proches de la machine

• Concevoir une solution était difficile sans de bonnes connaissances techniques.

– Cela impliquait que l’on proposait des solutions spécifiques, peu réutilisables

– A chaque fois on « réinventait la roue »

10 Ecrire ( "entrez une valeur positive pour j");20 Lire (j); 30 if j<0 then goto 10.../...

Page 37: Introduction à C++

Introduction à la programmation objet et générique avec C++ 37

Conception et « Orienté Objet » (7)Conception et « Orienté Objet » (7)✔ Vers les langages à objets (2)

– La méthode d’analyse « diviser pour régner »• on conçoit un ensemble de procédures pour résoudre le

problème– programmation dirigée par les traitements

• on décide d’abord de la manière dont on va manipuler les données puis on conçoit les structures de données pour faciliter cette manipulation.

– Rappel : une procédure (ou une fonction) est un regroupement d’instructions dans un bloc qui fournira un résultat (utile) et que l'on pourra appeler par son nom

void affichage(int i){ int j; printf( "entrez une valeur pour j"); scanf (&j); printf ("la variable passée en paramètre vaut : %d" ,i); printf ("la variable déclarée dans la procédure vaut: %d", j);}

Page 38: Introduction à C++

Introduction à la programmation objet et générique avec C++ 38

Conception et « Orienté Objet » (8)Conception et « Orienté Objet » (8)✔ Vers les langages à objets (3)

– La méthode d’analyse « diviser pour régner » :• Ces procédures reçoivent éventuellement des variables en

paramètres et effectuent des traitements sur ces variables données en paramètres ou sur des variables déclarées à l’intérieur de la procédure.

– Rappel : une variable est un morceau de mémoire auquel on donne un nom et dans lequel on stocke des valeurs.

void affichage(int i){ int j; printf( "entrez une valeur pour j"); scanf (&j); printf ("la variable passée en paramètre vaut : %d" ,i); printf ("la variable déclarée dans la procédure vaut: %d", j);}

Variable déclarée dans la procédure

Variable passée en paramètre

Procédure pour écrire sur la console et lire sur le clavier des informations

Page 39: Introduction à C++

Introduction à la programmation objet et générique avec C++ 39

Conception et « Orienté Objet » (9)Conception et « Orienté Objet » (9)✔ Vers les langages à objets (4)

– Dans l’approche procédurale• un programme est une suite de procédures qui s’exécutent

sur des données et produisent des données résultat, éventuellement réutilisées par d’autres procédures.

– Equation de Niklaus Wirth (père du Pascal et de Modula) :• Algorithmes + Structures de Données = Programmes

Page 40: Introduction à C++

Introduction à la programmation objet et générique avec C++ 40

Conception et « Orienté Objet » (10)Conception et « Orienté Objet » (10)✔ Vers les langages à objets (5)

– Exemple : une version simplifiée du 421 (1)• Si on fait 421 avec les 3 dés on gagne 100pts, si on fait

triple 6 on gagne 50pts, si on fait trois fois un chiffre quelconque différent de 6, on gagne 10pts et on ne gagne rien si on obtient un autre résultat.

– On souhaite implémenter cette version du 421, analyser le jeu sous forme de procédure

Page 41: Introduction à C++

Introduction à la programmation objet et générique avec C++ 41

Conception et « Orienté Objet » (11)Conception et « Orienté Objet » (11)✔ Vers les langages à objets (6)

– Exemple : une version simplifiée du 421 (2)

Procédure principale• démarrage du jeu en demandant à l’utilisateur son nom• lancement de la procédure simulant le jet de dés• récupération du résultat précédent et lancement de la procédure de test du résultat• récupération du résultat de la procédure précédente et ajout à la cagnotte du joueur• demander au joueur s’il veut continuer ou pas

Procédure de simulation du jet de dés• les dés n’existe pas en tant que tel. On « simule » juste par la procédure le jet des 3 dés. Le résultat est un tableau de 3 valeurs renvoyé par cette procédure.

Procédure de test du résultat du jet• Cette procédure prend en paramètre un tableau à 3 valeurs et en fonction de son contenu retourne une valeur correspondant à un gain.

Page 42: Introduction à C++

Introduction à la programmation objet et générique avec C++ 42

Conception et « Orienté Objet » (12)Conception et « Orienté Objet » (12)✔ Vers les langages à objets (7)

– Exemple : une version simplifiée du 421 (3)

Procédure de simulation du jet de dés ; retourne un tableau à 3 valeurs

Procédure principale

Procédure de test du résultat du jet; prend en paramètre un tableau à 3 valeurs ; retourne un gain;

Calcul du gain total

Page 43: Introduction à C++

Introduction à la programmation objet et générique avec C++ 43

Conception et « Orienté Objet » (13)Conception et « Orienté Objet » (13)✔ Vers les langages à objets (8)

– Limitation de l’approche procédurale :• Un changement dans la structure des données peut

entraîner de profondes modifications dans l'organisation des procédures.

– Les procédures/fonctions manipulent des structures de données spécifiques, et renvoie des valeurs correspondant à ces structures de données. Si on change la structure des données, on risque de devoir modifier plusieurs procédures

• Celles qui manipule directement les structures de données concernées

• Celles qui utilise les résultats des procédures précédentes.

– Dans l'’approche objet, on est encore dans une stratégie « diviser pour régner » mais ce ne sont plus les traitements que l’on fragmente 

Page 44: Introduction à C++

Introduction à la programmation objet et générique avec C++ 44

Conception et « Orienté Objet » (14)Conception et « Orienté Objet » (14)✔ L'approche objet (1)

– Programmation dirigé par les données et non par les traitements

• les procédures existent toujours mais on se concentre d’abord sur les entités que l’on va manipuler avant de se concentrer sur la façon dont on va les manipuler

– Notion d’encapsulation• les données et les procédures qui les manipulent (on parle

de méthodes ou de fonctions membres en C++) sont regroupés dans une même entité qui est nommée la classe.

Page 45: Introduction à C++

Introduction à la programmation objet et générique avec C++ 45

Conception et « Orienté Objet » (15)Conception et « Orienté Objet » (15)✔ L'approche objet (2)

– Notion de classe et d’objets : • la classe est un modèle décrivant les caractéristiques

communes et le comportement d’un ensemble d’objets – Pour désigner les objets, on utilise également le terme

d’instance d’une classe – la classe est un moule et l’objet est ce qui est produit

à partir de ce moule• Les caractéristiques communes des objets sont définis

dans la classe – les propriétés descriptives qui sont variables ou

constantes • on parle d’attributs, de champs, de propriétés

ou de données membres en C++– les comportement communs aux ensembles d’objets

• Ils sont représentés par les méthodes ou les fonctions membres en C++.

Page 46: Introduction à C++

Introduction à la programmation objet et générique avec C++ 46

Conception et « Orienté Objet » (16)Conception et « Orienté Objet » (16)✔ L'approche objet (3) : exemple

– On considère le constructeur automobile français Cinaultgeot qui commercialise depuis peu la Cléo 3.

– Chacune des Cléo 3 achetée par un particulier est différente et constitue un objet à part entière qui a une existence concrète.

• Chacune peut avoir une puissance différente, une couleur de carrosserie différente, des options différentes.

• Pourtant chacune à des caractéristiques communes et un comportement commun.

– Les couleurs de la carrosserie peuvent être différente, mais toutes ont une couleur de carrosserie (et une carrosserie ! :-)

– Toutes vont avoir une clé de contact, vont pouvoir être démarrer, vont pouvoir être manœuvrées avec un volant, etc.

Page 47: Introduction à C++

Introduction à la programmation objet et générique avec C++ 47

Conception et « Orienté Objet » (17)Conception et « Orienté Objet » (17)✔ L'approche objet (4) : exemple (suite)

– Pour des raisons de rentabilité de la production à la chaîne, Cinaultgeot a défini un plan de construction commun de cette voiture, en prenant bien soin de définir les parties variables communes de ces voitures

• En quelque sorte, et pour simplifier un peu, on a un plan commun à toutes les Cléo 3 et on sait quels vont être les parties variables (la couleur de la carrosserie par exemple).

• C’est lors de la réalisation concrète d’une Cléo 3 que l’on donne une valeur particulière à ces parties variables (par exemple telle voiture sera peinte en rouge, telle autre en noire)

– Chaque Cléo 3 créée est conçu pour réagir d’une certaine manière aux (inter)actions du conducteur

• Quand ce dernier agit sur le volant ou le levier de vitesse.• Cela fait partie des éléments relevant du comportement

commun à toutes les Cléo 3 définit dans les plans de constructions de cette voiture.

Page 48: Introduction à C++

Introduction à la programmation objet et générique avec C++ 48

Conception et « Orienté Objet » (18)Conception et « Orienté Objet » (18)✔ L'approche objet (5) : traduction de l'exemple en terme

« objet »– Chaque Cléo 3 créée correspond à un objet ou instance.– Le plan de construction des Cléo 3 correspond à une classe.

• Une classe est équivalent à un moule, à un plan de construction et l’objet est une entité concrète créée à partir de ce moule.

• Dans ce plan de construction– les parties variables comme la couleur de la

carrosserie correspondent aux attributs de l’objet.• Les attributs sont définis dans la classe (i.e. le

plan de construction) mais se voient affecter une valeur au moment de la création de l’objet.

– les comportements communs des voitures correspondent aux méthodes

• Une méthode correspond aux actions, aux messages auxquels peut réagir l’objet.

• Comme pour les attributs, ces méthodes sont définis dans la classe.

Page 49: Introduction à C++

Introduction à la programmation objet et générique avec C++ 49

Conception et « Orienté Objet » (19)Conception et « Orienté Objet » (19)✔ L'approche objet (6) : notation graphique

+démarrer()+conduire()

+couleur_carroserie+puissance

Cléo 3

La classe

Nom de la classe

Attributs de la classe

Méthodes de la classe

Page 50: Introduction à C++

Introduction à la programmation objet et générique avec C++ 50

Conception et « Orienté Objet » (20)Conception et « Orienté Objet » (20)✔ L'approche objet (7) : notion d'encapsulation (1)

– les données et les procédures qui les manipulent sont regroupées dans une même entité, l'objet.

– Les détails d'implémentation sont cachés, le monde extérieur n'ayant accès aux données que par l'intermédiaire d'un ensemble d'opérations constituant l'interface de l'objet.

– Le programmeur n'a pas à se soucier de la représentation physique des entités utilisées et peut raisonner en termes d'abstractions.

+démarrer()+conduire()

+couleur_carroserie+puissance

Cléo 3

Page 51: Introduction à C++

Introduction à la programmation objet et générique avec C++ 51

Conception et « Orienté Objet » (21)Conception et « Orienté Objet » (21)✔ L'approche objet (8) : notion d'encapsulation (2)

– Avec la POO, nous sommes dans une programmation dirigée par les données

• pour concevoir une application, le programmeur commence par définir les classes d'objets appropriées, avec leurs méthodes spécifiques.

– En définissant de nouvelles classes le programmeur définit de nouveau type de données

– Ces nouveaux types de données sont plus adaptés pour décrire le domaine de l'application que les types de bases.

• On considère ce que doivent être les objets manipulés par le programme, on essaie d’extraire leurs caractéristiques communes et de définir différentes classes qui définiront ces objets

Page 52: Introduction à C++

Introduction à la programmation objet et générique avec C++ 52

Conception et « Orienté Objet » (22)Conception et « Orienté Objet » (22)✔ L'approche objet (9) : notion d'encapsulation (3)

– La plupart du temps on part de la situation concrète– Puis on remonte vers une « généralisation », « une

abstraction » : la classe • La classe est le plan de construction des futurs objets

manipulés par le programme et la description de leur comportement

• chaque entité manipulée dans le programme est un représentant (ou instance) d'une de ces classes.

• « l'univers de l'application » est par conséquent composé d'un ensemble d'objets définis et créés à partir de la définition d’une classe.

– Les caractéristiques statiques (propriétés variables et constantes) et les caractéristiques dynamqiues (i.e. le comportement) de ces objets sont définis dans la classe.

Page 53: Introduction à C++

Introduction à la programmation objet et générique avec C++ 53

Conception et « Orienté Objet » (23)Conception et « Orienté Objet » (23)✔ L'approche objet (10) : exemple

– Comment, ici selon une approche objet, analyser et modéliser le jeu de 421 que nous avons analyser tout à l’heure de manière procédurale ?

Page 54: Introduction à C++

Introduction à la programmation objet et générique avec C++ 54

Conception et « Orienté Objet » (24)Conception et « Orienté Objet » (24)✔ L'approche objet (11) : exemple (suite)

+calculerGain()

+unJoueur+Dés

Jeu421

+seCréer(uneChaine)()+jouer()

+nom-gain

Joueur

+seCréer()+seLancer()+doonnerSaValeur()

+valeur_affichéeDé

unJeu421

unJoueur

De1De2

De3

Les objets Les classes

Page 55: Introduction à C++

Introduction à la programmation objet et générique avec C++ 55

Conception et « Orienté Objet » (25)Conception et « Orienté Objet » (25)✔ L'approche objet (12) : exemple (suite)

UnJoueurunJeu421

seCréer(unNom)

De1

seCréer

De2

seCréer

De3

seCréer

Jouer

seLancer

seLancer

seLancer

Page 56: Introduction à C++

Introduction à la programmation objet et générique avec C++ 56

Conception et « Orienté Objet » (26)Conception et « Orienté Objet » (26)✔ L'approche objet (13) : exemple (fin)

– Pour résumer• A partir de l’application principale (dans l’exemple cela

correspond à la classe jeu421 et l’objet unJeu421), – on crée différents objets à partir des classes que nous

avons au préalable définies. • L’application résultante est le résultat de l’interaction entre

ces différents objets par l’intermédiaire des méthodes.

Page 57: Introduction à C++

Introduction à la programmation objet et générique avec C++ 57

Conception et « Orienté Objet » (27)Conception et « Orienté Objet » (27)✔ La classe

– Classe : description d’une famille d’objets ayant une même structure et un même comportement.

– Elle est caractérisée par :• Un nom• Une composante statique :

– des attributs (ou champs ou propriétés ou données membres) nommés ayant une valeur.

– Les attributs caractérisent l’état des objets pendant l’exécution du programme

• Une composante dynamique : – des méthodes (ou fonctions membres en C++)

représentant le comportement des objets de cette classe.

– Les méthodes manipulent les attributs des objets et caractérisent les actions pouvant être effectuées par les objets.

– En C++, définir une classe c'est définir un nouveau type de données utilisateur.

Page 58: Introduction à C++

Introduction à la programmation objet et générique avec C++ 58

Conception et « Orienté Objet » (28)Conception et « Orienté Objet » (28)✔ Représentation graphique d'une classe

HommeAge : IntegerTaille : DoublePoids : DoubleNom : String

parle()mange()boit()dort()

Une classe représentée avec la notation UML (Unified Modeling Language)

Nom

Méthodes

Attributs

Page 59: Introduction à C++

Introduction à la programmation objet et générique avec C++ 59

Conception et « Orienté Objet » (29)Conception et « Orienté Objet » (29)✔ Instanciation et instance

– Instanciation • concrétisation d’une classe en un objet « concret ».

– Dans nos programmes C++ nous allons définir des classes et instancier ces classes en des objets qui vont interagir.

• Le fonctionnement du programme résulte de l’interaction entre ces objets « instanciés ».

• Lors de l’instanciation ou au cours de la « vie » de l’objet, les attributs qui représentent ce qui va varier entre objets d’une même classe, vont éventuellement prendre des valeurs particulières

– En Programmation Orientée Objet, on décrit des classes et l’application en elle-même est constituée des objets instanciés à partir de ces classes, qui vont communiquer et agir les uns sur les autres.

– On parle d'instance de classe pour désigner les « objets » créés à partir d'une classe. Par abus de langage on parle souvent juste d'objet.

Page 60: Introduction à C++

Introduction à la programmation objet et générique avec C++ 60

Conception et « Orienté Objet » (30)Conception et « Orienté Objet » (30)✔ Instanciation et instance : exemple

– si nous avons une classe voiture, alors votre voiture est une instance particulière de la classe voiture.

• Classe = concept, description, plan• Objet = représentant concret d’une classe

Page 61: Introduction à C++

Introduction à la programmation objet et générique avec C++ 61

Conception et « Orienté Objet » (31)Conception et « Orienté Objet » (31)✔ Héritage : exemple introductif (1)

– On souhaite réaliser un jeu vidéo de type « wargame » • Le joueur manipule des petites entités que nous

nommerons ici « personnage », qu’il utilise pour conquérir des territoires ou défendre les siens.

• Il y a différents types de personnage, ayant sur certains points des caractéristiques communes et des différences entre eux.

Page 62: Introduction à C++

Introduction à la programmation objet et générique avec C++ 62

Conception et « Orienté Objet » (32)Conception et « Orienté Objet » (32)✔ Héritage : exemple introductif (2)

– On considère ici un « wargame » de type moyen-ageux et fantastique (dans le style « Warcraft ™ »), avec, pour simplifier, comme types de personnage des guerriers, des magiciens, des prêtres et des paysans.

• Les guerriers savent manier les armes et se battre. On distingue parmi eux les fantassins et les cavaliers. Les cavaliers sont identiques aux fantassins mais savent en plus monter et se battre à cheval

• Les prêtres sont les seuls à savoir soigner• Les magiciens sont les seuls à pouvoir lancer des

sortilèges et à avoir des points de magie• Les paysans sont les seules à pouvoir produire de la

nourriture.• Tous les personnages consomment de la nourriture, ont

une durée de vie, un nombre de point de vie, une valeur représentant leur force, leur résistance à la magie, etc.

Page 63: Introduction à C++

Introduction à la programmation objet et générique avec C++ 63

Conception et « Orienté Objet » (33)Conception et « Orienté Objet » (33)✔ Héritage : exemple introductif (3)

– Comment concevoir ces différents « personnages » et types de personnages selon une démarche « orientée objet » ?

Page 64: Introduction à C++

Introduction à la programmation objet et générique avec C++ 64

Conception et « Orienté Objet » (34)Conception et « Orienté Objet » (34)✔ Héritage : exemple introductif (4)

– Comment concevoir ces différents « personnages » et types de personnages selon une démarche « orientée objet » ?

• Première solution– A un type de personnage ont fait directement

correspondre une classe

+seBattre()+seNourrir()

+pointDeVie+force

Fantassin

+seBattre()+seNourrir()+seBattreACheval()

+pointDeVie+force

cavalier+lancerSort()+seNourrir()

+pointDeVie+force-pointdeMagie

Magicien+guerir()+seNourrir()

+pointDeVie+force

Prêtre

+produire()+seNourrir()

+pointDeVie+force

Paysan

Page 65: Introduction à C++

Introduction à la programmation objet et générique avec C++ 65

Conception et « Orienté Objet » (35)Conception et « Orienté Objet » (35)✔ Héritage : exemple introductif (5)

– Comment concevoir ces différents « personnage » avec une vision par objet ?

• Première solution : correspondance directe entre un type de personnage et une classe

– Avec cette première solution se qui est dommage, c’est qu’un même comportement (seNourrir) devra être défini pour chacune des différentes classes

– Il semble dommage de ne pas avoir un mécanisme qui nous permettrait de mieux organiser nos classes

• Après tout, du guerrier au prêtre, se sont tous des personnages qui se nourrissent, ont des points de vie, etc. Ils sont caractérisées par un ensemble de propriétés communes et se distinguent seulement par quelques propriétés différentes.

Page 66: Introduction à C++

Introduction à la programmation objet et générique avec C++ 66

Conception et « Orienté Objet » (36)Conception et « Orienté Objet » (36)✔ Héritage : exemple introductif (6)

– Comment concevoir ces différents « personnage » avec une vision par objet ?

• La première solution que nous avons proposer établisser une correspondance directe entre un type de personnage et une classe.

• Cependant, il serait pratique– de définir un ensemble minimum de propriétés et de

comportement communs – de faire en sorte que chaque classe les possède, les

hérite– d'ajouter dans chacune des classes ce qui les

distinguent des autres classes.• Ce mécanisme existe dans les langages de classe, c’est le

mécanisme d’héritage.• Ce qui nous mène vers une deuxième solution...

Page 67: Introduction à C++

Introduction à la programmation objet et générique avec C++ 67

Conception et « Orienté Objet » (37)Conception et « Orienté Objet » (37)✔ Héritage : exemple introductif (7)

• Une deuxième solution : utilisation de l'héritage

Fantassin

+seBattreACheval()

cavalier

+lancerSort()-pointdeMagie

Magicien

+guerir()

Prêtre

+produire()

Paysan

+seBattre()+seNourrir()

Guerrier

+seNourrir()

+pointDeVie+force

Personnage

Page 68: Introduction à C++

Introduction à la programmation objet et générique avec C++ 68

Conception et « Orienté Objet » (38)Conception et « Orienté Objet » (38)✔ Héritage : exemple introductif (8)

– Deuxième solution : utilisation de l’héritage• Avec l’héritage il y a factorisation du code : on partage le

code commun– On écrit moins de code (normalement), gain de place

et de temps de développement, même s’il peut y avoir plus de classes

– On a moins de modifications à faire• Si je décide de modifier la méthode seNourrir(),

avec la première solution, il faudra que je le fasse pour chaque méthode dans chaque classe.

• Avec l’héritage, je ne ré-écris qu’une méthode• L'héritage est également un puissant moyen d'organiser

ces classes, et donc son code.

Page 69: Introduction à C++

Introduction à la programmation objet et générique avec C++ 69

Conception et « Orienté Objet » (39)Conception et « Orienté Objet » (39)✔ Héritage : définition

– L'héritage est un mécanisme permettant le partage et la réutilisation de propriétés entre les objets.

– La relation d’héritage est une relation de généralisation / spécialisation.

• La classe parente est la superclasse, la classe qui hérite est la sous-classe.

Page 70: Introduction à C++

Introduction à la programmation objet et générique avec C++ 70

Conception et « Orienté Objet » (40)Conception et « Orienté Objet » (40)✔ Héritage : réprésentation graphique

– La relation d’héritage est une relation de généralisation / spécialisation.

Représentation avec UML d’un héritage (simple)

Conducteur

conduire()demarrer()

HommeAge : IntegerTaille : DoublePoids : DoubleNom : String

parle()mange()boit()dort()

Super classe

Lien d’héritage classe

Sous classe

Page 71: Introduction à C++

Introduction à la programmation objet et générique avec C++ 71

Conception et « Orienté Objet » (41)Conception et « Orienté Objet » (41)✔ Envoi de message

– les objets interagissent en envoyant des messages aux autres objets (et éventuellement à eux-mêmes)

– Ce sont les méthodes qui correspondent à ces envois de message

• On demande en quelque sorte à l’objet de réaliser la série d’instructions contenue dans sa méthode.

unConducteur : Conducteur uneVoiture : Voiture

demarrer( )

mettreContact( )

conduire( )

acceler( )

Diagramme de séquence UML

Conducteur

conduire()demarrer()

PossedeVoiture

mettreContact()freiner()acceler()

Envoi de message d’un objet à un autre.Attention! On est bien au niveau des instances et pas des classes

Diagramme de classes UML

Page 72: Introduction à C++

Introduction à la programmation objet et générique avec C++ 72

Conception et « Orienté Objet » (42)Conception et « Orienté Objet » (42)✔ Des concepts à la pratique

– C++ est un langage objet dit « de classe ». • Un programme en C++ se présente comme la définition

d’un ensemble de classes. • Ces classes sont instanciées en objet dans la fonction

« main », point d'entrée de notre programme– Dans le « main », on met des instructions qui

permettent de créer des objets, – on appelle des méthodes sur ces objets (c’est-à-dire

qu’on envoie des messages aux objets), ces méthodes en appelleront éventuellement d’autres, etc…

– Le programme en lui-même résulte de l’interaction entre les différents objets instanciés.

Page 73: Introduction à C++

Introduction à la programmation objet et générique avec C++ 73

Conception et « Orienté Objet » (43)Conception et « Orienté Objet » (43)✔ Conception et programmation C++ (1)

– Idéalement la conception d'un programme se déroule en 3 phases

• D'abord une compréhension claire du problème• Puis une identification des concepts clefs impliqués dans

une solution• Finalement l'expression de cette solution dans un

programme– Il existe des concepts qui ne sont pas facilement représentés

par un des types fondamentaux ou par une fonction sans donnée statique associée

• Un tel concept est représentée par une classe dans un langage orienté objet comme C++

– Une classe est un type • i.e. quelle précise comment les objets de cette classe se

comportent : comment ils sont créés, comment ils peuvent être manipulés et comment ils sont détruits.

Page 74: Introduction à C++

Introduction à la programmation objet et générique avec C++ 74

Conception et « Orienté Objet » (44)Conception et « Orienté Objet » (44)✔ Conception et programmation C++ (2)

– Un clé pour écrire un bon programme est de concevoir des classes de telle façon que chacune d'elle ne représente qu'un seul concept

• Cela signifie souvent que le programmeur doit se concentrer sur les questions suivantes

– Comment les objets de cette classe sont-ils créés ?– Les objets de cette classe peuvent-ils être

copiés/détruits ?– Quelles opérations peuvent être faites sur de tels

objets ?• S'il n'y a pas de bonnes réponses à ces questions,

le concept n'est probablement pas « clairement défini » dès le début.

• Il serait alors bon de penser un peu au problème et à la solution proposée au lieu de commencer à coder pour contourner le problème.

Page 75: Introduction à C++

Introduction à la programmation objet et générique avec C++ 75

Conception et « Orienté Objet » (45)Conception et « Orienté Objet » (45)✔ Conception et programmation C++ (3)

– Un concept n'existe pas seul : il y a toujours des groupes de concepts rattachés

• Organiser les relations entre les classes dans un programme (i.e. déterminer les relations exactes entre les différents concepts impliqués dans une solution) est souvent plus difficile que d'ébaucher les classes individuellement

– Un des outils intellectuels les plus puissants pour gérer la complexité est l'ordre hiérarchique, i.e. l'organisation des concepts dépendants en une structure d'arbre, avec le concept le plus général comme racine

• En C++ ou en Java, et de manière générale dans les langages de classes, les classes dérivées représentent de telles structures.

• Un programme peut souvent être organisé comme un ensemble d'arbres ou de graphes acycliques orientés de classes.

Page 76: Introduction à C++

Introduction à la programmation objet et générique avec C++ 76

Conception et « Orienté Objet » (46)Conception et « Orienté Objet » (46)✔ Conception et programmation C++ (4)

– La question « comment écrit-on un bon programme en C++ ? » est très similaire à la question « comment écrit-on une bonne prose en français ? » ;

• il existe 2 formes de réponse– Sachez ce que vous voulez dire– Pratiquez et imitez les bons auteurs

• Ces 2 réponses sont appropriées à C++ (à Java et n'importe qu'elle autre langage) comme au français (ou à toute autre « langage naturelle ») ...

• ... et aussi difficile à suivre– Il faut essayer de penser un programme comme un ensemble

de concepts agissant réciproquement représentés par des classes et des objets,

• Au lieu de le penser comm un ensemble de structures de données avec des fonctions manipulant les octets de ces structures de données.

Page 77: Introduction à C++

Introduction à la programmation objet et générique avec C++ 77

Conception et « Orienté Objet » (47)Conception et « Orienté Objet » (47)✔ Quelques règles empiriques à considérer pour la POO en

C++– Quelques règles que vous devriez considérer lors de votre

apprentissage du C++, proposées par B. Stroustrup himself• Elles sont volontairement simples et c'est à vous de les

faire évoluer avec votre pratique• Ecrire un bon programme demande de l'intelligence, du

goût et de la patience : c'est difficile, il faut pratiquer– Quand vous programmez, vous créez une représentation

concrète des idées, de solutions à certains problèmes.– Laissez la structure du programme refléter ces idées aussi

directement que possible :• Si vous pouvez « la » voir comme une idée séparée, faites

en une classe.• Si vous pouvez « la » voir comme une entité séparée,

faites en un objet d'une certaine classe• Si deux classes ont quelques choses en commun, faites

de cette relation commune une classe de base.• Si une classe contient des objets, faites en un patron.

Page 78: Introduction à C++

Introduction à la programmation objet et générique avec C++ 78

Conception et « Orienté Objet » (48)Conception et « Orienté Objet » (48)✔ Quelques règles empiriques à considérer pour la POO en

C++– Quand vous définissez une classe qui ne réalise pas une

entité mathématique comme une matrice ou un nombre complexe, ou un type de bas niveau comme une liste chaînée :

• N'utilisez pas de variable globale• N'utilisez pas de fonctions globales (i.e. une fonction non

membre).• N'utilisez pas de champs membres « public » (i.e. Visible

et accessible par tous).• N'utilisez pas le mécanisme « ami », sauf pour éviter les 3

précédentes• N'accédez pas directement aux champs membres d'un

autre objet.• Ne mettez pas un « champ de type » dans une classe ;

utilisez plutôt les fonctions virtuelles.• N'utilisez pas les fonctions en ligne (inline), sauf pour une

optimisation significative.

Page 79: Introduction à C++

Introduction à la programmation objet et générique avec C++ 79

Conception et « Orienté Objet » (49)Conception et « Orienté Objet » (49)✔ Quelques remarques sur ces règles empiriques

– Ces règles sont à conserver et à reconsulter fréquemment... à ce stade du cours elles ne vous sembleront probablement pas d'un grand secours.

– Ce ne sont que quelques règles empiriques, à vous de les compléter.

– Elles s'appliquent bien au C++, et pour certaines à d'autres langages comme Java...

• ... mais attention, pour certains autres langages dans laquelle la « vision objet » est subtilement différente, elles ne seront peut-être pas tout aussi adaptées.

Page 80: Introduction à C++

Introduction à la programmation objet et générique avec C++ 80

Les cartes CRC (1)Les cartes CRC (1)✔ Présentation

– Les cartes CRC sont des fiches cartonnées claissques qui sont utilisées pour représenter les responsabilité d'une classes et ces interactions avec les autres classes.

– Les cartes CRC sont une approche « informelle » à la « modélisation objet ».

– Ces cartes sont créées à travers des scénarii, basés sur les exigence système qui modélise le comportement du système.

– CRC = Class, Responsabilities and Collaborators• Ce sont pour les créateurs des cartes CRC, les notions de

Classe, de Responsabilité et de Collaborateur représentent les dimensions essentielles de la modélisation objet.

– Les cartes CRC ont été proposés par Kent Beck et Ward Cunningham.

– Initialement c'était une technique mise au point pour l'apprentissage de la modélisation objet. Elles sont devenues une technique d'analyse et de conception reconnue

• Elles sont utilisées notamment en eXtreme Programming (XP).

Page 81: Introduction à C++

Introduction à la programmation objet et générique avec C++ 81

Les cartes CRC (2)Les cartes CRC (2)✔ Description (1)

– Un modèle CRC est une série de fiches cartonnées qui ont été divisées en 3 sections

• Une classe représente un ensemble d'objet similaire.• Une responsabilité est quelque chose qu'une classe

connait ou fait.• Un collaborateur est une autre classe avec laquelle la

classe interagit pour accomplir ses responsabilités. Une collaboration peut prendre 2 formes : une requête pour une information ou une requête pour faire quelque chose.

Responsabilités :

Nom de la classe :

Collaborateurs :

Page 82: Introduction à C++

Introduction à la programmation objet et générique avec C++ 82

Les cartes CRC (3)Les cartes CRC (3)✔ Description (2)

– On peut aussi dans certains cas faire apparaître les superclasses et les sous classes de la classe sur la carte mais ce n'est pas une obligation.

Collaborateurs :Responsabilités :

Sous-classes :

Superclasses :

Nom de la classe :

Page 83: Introduction à C++

Introduction à la programmation objet et générique avec C++ 83

Les cartes CRC (4)Les cartes CRC (4)✔ Description (3)

– Le dos de la carte peut-être utilisé pour une description plus « littéraire » de la classe ou lors d'une utilisation en phase de conception pour détailler les attributs de la classe.

• Une manière de voir les choses est de considérer qu'il y a une face représentant les informations publiques et que le dos de la fiche représente les détails d'implémentation « encapsulés ».

Page 84: Introduction à C++

Introduction à la programmation objet et générique avec C++ 84

Les cartes CRC (5)Les cartes CRC (5)✔ Une session de modélisation avec les cartes CRC (1)

– La taille idéale pour une session de cartes CRC est de 5 à 6 personnes

• Ce n'est donc pas évident de pouvoir faire une session de cartes CRC dans toutes les situations.

• Une solution s'il y a trop de personnes, est qu'une partie des participants soient uniquement « observateur ».

• Si vous êtes peu nombreux (2, 3 ou 4 personnes). Cela peut quand même être intéressant d'essayer de le faire.

– Pour schématiser, une session de cartes CRC peut-être vue comme une sorte de « brainstorming orienté objet ».

– Même seul cela peut guider votre démarche d'analyse et de conception

• Cela peut être fait avec le client. Il est même recommandé qu'il y ait au moins une personne experte du domaine de l'application dans le groupe.

– Une session CRC peut être utilisée en phase d'analyse et/ou en phase de conception.

Page 85: Introduction à C++

Introduction à la programmation objet et générique avec C++ 85

Les cartes CRC (6)Les cartes CRC (6)✔ Une session de modélisation avec les cartes CRC (2)

– Le préalable nécessaire à toute session est qu'il y ait une forme ou une autre d'expression des besoins et des exigence du système

– Dans une session CRC, il faut aussi se concentrer sur un aspect du problème à la fois (surtout si c'est un « grand » système que l'on cherche à modéliser).

• Il faut donc parfois choisir d'explorer un sous-ensemble des besoins exprimés lors d'une session CRC.

Page 86: Introduction à C++

Introduction à la programmation objet et générique avec C++ 86

Les cartes CRC (7)Les cartes CRC (7)✔ Une session de modélisation avec les cartes CRC (3)

– Trouver les classes• La première étape dans la modélisation d'un système dans

un carde « objet » est d'identifier les classes dans le domaine de l'application.

• En utilisant les exigences du systèmes ou les besoins exprimées, vous allez identifier les classes les plus évidentes dans le problème exploré dans la session

• Une manière de faire est de trouver tous les noms et tous les verbes dans le document présentant le problème

– Les noms aident en général à trouver quelles classes il y a aura dans le système

– Les verbes montrent en général ce que seront les responsabilités

Page 87: Introduction à C++

Introduction à la programmation objet et générique avec C++ 87

Les cartes CRC (8)Les cartes CRC (8)✔ Une session de modélisation avec les cartes CRC (4)

– Trouver les classes (suite)• C'est une première phase de type brainstorming, i.e. Que

l'on ne discute pas ou peu les idées à ce moment-là.• On note les classes trouvées• Puis on choisit et filtre les classes• Une fois que l'on a arrêté une liste de classes, on répartit

les classes entre les participants et on distribue des fiches cartonnées à chacun

– Chaque personne doit être responsable d'au moins une classe

– Cette personne est le propriétaire de cette ou de ces classe(s) pour cette session

– Elle note sur sa ou ses cartes le nom de sa ou ses classes

• Une classe par carte CRC.

Page 88: Introduction à C++

Introduction à la programmation objet et générique avec C++ 88

Les cartes CRC (9)Les cartes CRC (9)✔ Une session de modélisation avec les cartes CRC (5)

– Définir les responsabilités• Une fois que l'on a un ensemble de classes, on va leur

ajouter des responsabilités– On va ajouter les responsabilités les plus évidentes

d'après les exigences ou le nom de la classe.– Il n'est pas nécessaire de trouver toutes les

responsabilités immédiatement• Les scénarii en rendront d'autres plus évidentes

par la suite.– L'avantage d'en trouver quelques unes au début est

que cela aide pour démarrer.– Définir les sous classes et les superclasses

• Selon les cas ce n'est pas forcément nécessaire d'en parler

• On peut les définir dès quelles semblent évidentes• Les scénarii devraient les mettre en exergue de toutes

façons.

Page 89: Introduction à C++

Introduction à la programmation objet et générique avec C++ 89

Les cartes CRC (10)Les cartes CRC (10)✔ Une session de modélisation avec les cartes CRC (6)

– Les attributs• Il ne faut pas être trop pressé de les définir

– Normalement ils ne sont pas définis avant la phase de conception

• Néanmoins, ils peuvent être définis dès l'instant où le groupe pense que c'est pertinent de le faire

– Rappelez-vous que ce sont des détails d'implémentation, et qu'il faut donc les mettre au dos de la carte

Page 90: Introduction à C++

Introduction à la programmation objet et générique avec C++ 90

Les cartes CRC (11)Les cartes CRC (11)✔ Une session de modélisation avec les cartes CRC (7)

– Les scenarii• Pour définir un scenario, on part des fonctionnalités

attendues du système.– On commence par des « cas d'utilisation » normaux

avant d'intégrer des scenarii plus exceptionnels prenant en compte des cas limites ou des situations à problème

• Une fonctionnalité = ensemble de fonctions• En premier il faut décider quelle classe est responsable

pour la fonction de départ de la fonctionnalité que l'on veut « tester ».

– Le propriétaire de la carte l'a prend et la place en l'air.– Une carte ainsi « en l'air » est considérée comme un

objet et peut donc « faire des choses ».– Le propriétaire précise ce dont il a besoin pour

accomplir sa responsabilité.– Si possible, la responsabilité est affinée en tâches plus

petites.

Page 91: Introduction à C++

Introduction à la programmation objet et générique avec C++ 91

Les cartes CRC (12)Les cartes CRC (12)✔ Une session de modélisation avec les cartes CRC (8)

– Les scenarii (suite)• En premier il faut décider quelle classe est responsable

pour la fonction de départ de la fonctionnalité que l'on veut « tester ».

– Le propriétaire de la carte l'a prend et la place en l'air.– Une carte ainsi « en l'air » est considérée comme un

objet et peut donc « faire des choses ».– Le propriétaire précise ce dont il a besoin pour

accomplir sa responsabilité.– Si possible, la responsabilité est affinée en tâches plus

petites. • Ces tâches plus petites sont réalisées directement

par l'objet ou sont réalisés par l'objet en coopération avec d'autres objets.

• Il est possible que l'on s'aperçoive alors qu'il manque une classe et que l'on en définisse une nouvelle.

Page 92: Introduction à C++

Introduction à la programmation objet et générique avec C++ 92

Les cartes CRC (13)Les cartes CRC (13)✔ Une session de modélisation avec les cartes CRC (9)

– Phase d'analyse• La phase d'analyse est le processus qui modélise ce que

fait le système– Attention pendant la phase d'analyse on s'intéresse

juste à ce qu'est sensé faire le système pas à la manière dont il le fait !

• Comment sait-on que la pahse d'analyse est terminée ?– Quand les différentes responsabilités sont en place et

que le système est « stable ».• Quand tous les scénarii avec les « comportements

normaux » ont été couverts, il faut passer aux comportements exceptionnels.

• Quand il n'y a plus besoin d'ajouter ou de modifier les responsabilités (ou très peu) et qu'il n'y a pas de classes à ajouter pour prendre en compte les nouveaux scénarii, cela signifie que l'on peut certainement passer à la phase de conception

Page 93: Introduction à C++

Introduction à la programmation objet et générique avec C++ 93

Les cartes CRC (14)Les cartes CRC (14)✔ Une session de modélisation avec les cartes CRC (10)

– Phase de conception• Dans la phase de conception on ne se demande plus ce

que fait le système mais comment il le fait.• Au niveau de classes

– Il faut se demander quelles classes sont nécessaires au fonctionnement du système

– Les nouvelles classes que l'on va rechercher dans cette phase sont celles qui vont servir à l'implementation du système.

Page 94: Introduction à C++

Introduction à la programmation objet et générique avec C++ 94

Les cartes CRC (15)Les cartes CRC (15)✔ Une session de modélisation avec les cartes CRC (11)

– Phase de conception (suite)• Au niveau des scénarii, objets et classes

– Durant la phase d'analyse la distinction entre classes et objets est floue. Dans la phase de conception, il faut maintenant penser aux objets

• Qui crée les objets ? Que se passent-ils lorsqu'ils sont créés et détruits ? Quelle est la durée de vie d'un objet par rapport à la durée de vie de l'information qu'il détient ?

• Au niveau des attributs– On peut maintenant regarder plus précisément quelles

informations les objets détiennent, par rapport à ce qui obtenue d'autres classes ou calculée à la volée.

– On utilise le dos des fiches pour écrire les attributs.

Page 95: Introduction à C++

Introduction à la programmation objet et générique avec C++ 95

Les cartes CRC (16)Les cartes CRC (16)✔ Une session de modélisation avec les cartes CRC (12)

– Phase de conception (fin)• Ajouts sur les cartes

– Sous-responsabilités• Diviser les responsabilités en sous-responsabilités

placée sour la responsabilités principales• Placer les collaborateurs à proximité de la sous-

responsabilités qui les utilise– Collaborateurs

• A la suite des collaborateurs sur votre carte, listées les responsabilités de la classe actuelle qui sont utilisées dans la collaboration

▪ On parlera de « responsabilités colloboratives »– Echange de données

• A la suite des « responsabilités collaboratives », listez les données retournées par le collaborateur.

Page 96: Introduction à C++

Introduction à la programmation objet et générique avec C++ 96

Généralités sur le C++

Page 97: Introduction à C++

Introduction à la programmation objet et générique avec C++ 97

Plan général du coursPlan général du cours✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques

• Livre• Web

– Les outils utilisés dans ce cours✔ Introduction aux concepts de la programmation orientée

objet– Conception et « Orienté Objet »– Les cartes CRC

✔ Introduction au C++– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 98: Introduction à C++

Introduction à la programmation objet et générique avec C++ 98

Introduction au C++ (1/4) : sommaireIntroduction au C++ (1/4) : sommaire✔ Introduction au C++

– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 99: Introduction à C++

Introduction à la programmation objet et générique avec C++ 99

Généralités sur le C++ (1)Généralités sur le C++ (1)

Procédure de création d'un programme à partir d'un ou plusieurs fichiers en C/C++

CompilationCompilation

Fichier(s) de code

Code objet

Fichier(s) en- tête

Code objet Edition de liens

Autres code objet

Librairies

Edition de liens

Autres code objet

Librairies

Autres code objet

Librairies

Programme exécutableProgramme exécutable

Fichiers avec l'extension .c

Fichiers avec l'extension .h

Fichiers avec l'extension .ogénérée par la compilation

Rappel : du code source au programme

Page 100: Introduction à C++

Introduction à la programmation objet et générique avec C++ 100

Généralités sur le C++ (2) : un premier programmeGénéralités sur le C++ (2) : un premier programme

#include <cstdlib>#include <iostream>

/* Un programme très utile */int main (){ //Ecriture sur le terminal std::cout << "La programmation avec C++, c'est trop fou!!!" << std::endl; //un appel système system("PAUSE"); return 0;}

Des commentaires

Pour inclure des fonctions prédéfinies(inclusion de bibliothèques)

Ecriture sur le terminal

Fonction principale :point d'entrée dans le programme

Ne pas oublier les points-virgules en fin de ligne

Page 101: Introduction à C++

Introduction à la programmation objet et générique avec C++ 101

Généralités sur le C++ (3) : un deuxième programmeGénéralités sur le C++ (3) : un deuxième programme

#include <cstdlib>#include <iostream>using namespace std;

/* Un programme très utile */int main (){ //Ecriture sur le terminal cout << "La programmation avec C++, c'est trop fou!!!" << endl; //un appel système system("PAUSE"); return 0;}

Pour inclure des fonctions prédéfinies(inclusion de bibliothèques)

Ecriture sur le terminal

Définition d'un espace de nom

Page 102: Introduction à C++

Introduction à la programmation objet et générique avec C++ 102

Généralités sur le C++ (4) : un « meilleur C »Généralités sur le C++ (4) : un « meilleur C »✔ Le préprocesseur (rappel)

– Le compilateur C/C++ contient un utilitaire : le préprocesseur• Il agit au niveau des fichiers contenant les programmes

C/C++ et fournit les fonctionnalités suivantes– Définition et manipulation de macro-instructions avec

ou sans arguments• Par exemple des fonctions ou de petite macro

– Inclusion de fichier– Traitement conditionnel du fichier– Directives pour la compilation

• Pour adapter le compilateur à un environnement particulier

• En C++, de manière générale, on utilisera moins les définitions de constantes ou de macro-instructions via les #define que l'on pouvait le faire en C

Page 103: Introduction à C++

Introduction à la programmation objet et générique avec C++ 103

Généralités sur le C++ (5) : un « meilleur C »Généralités sur le C++ (5) : un « meilleur C »✔ Fonctionnement du préprocesseur (rappel)

– Le préprocesseur évalue les fichiers « source » ligne par ligne et reconnaît les lignes commençant par le caractère « # » comme des lignes contenant des directives de prétraitement qui lui sont propres

• Ces directives sont définies à l'avance– On ne peut pas définir ses propres directives

• Le préprocesseur ne s'intéresse qu'aux lignes contenant des directives

– Les autres lignes sont soit ignorées, soit traitées en fonction des directives précédemment rencontrées.

Page 104: Introduction à C++

Introduction à la programmation objet et générique avec C++ 104

Généralités sur le C++ (6) : un « meilleur C »Généralités sur le C++ (6) : un « meilleur C »✔ Définition et manipulation de macro-instructions

– #define <ident> <definition>• Définit <ident> comme une macro-instruction• Dans toutes les lignes sources qui suivent, jusqu'à la fin du

fichier ou jusqu'à un #undef <ident>, il remplacera toute occurrence de <ident> par le contenu de définition.

– #define PI 3.141592– ...– int x = PI; // équivaut à int x = 3.141592

✔ Définition de macro-instructions avec arguments– #define <ident> (<args>) <definition>– Le nombre d'arguments présents dans la définition doit être

respecté lors de l'appel de cette même macro-instruction• #define sum(x,y) (x+y)• #define max(a,b) (a<b)?b:a

Page 105: Introduction à C++

Introduction à la programmation objet et générique avec C++ 105

Généralités sur le C++ (7) : un « meilleur C »Généralités sur le C++ (7) : un « meilleur C »✔ Inclusion de fichiers

– Une directive pour inclure le contenu d'un fichier désigné– #include <nom_fichier>

• Pour inclure les fichiers de la bibliothèque standard• #include <stdio.h> (C)• #include <iostream> (C++)

– #include "nom_fichier"• Pour inclure les fichiers définis par l'utilisateur• #include "myLib.h" (C/C++)

Page 106: Introduction à C++

Introduction à la programmation objet et générique avec C++ 106

Généralités sur le C++ (8) : un « meilleur C »Généralités sur le C++ (8) : un « meilleur C »✔ Bloc

– Un bloc en C/C++ est délimité par des accolades : { } ✔ Procédure et fonction

– Il n'y a pas de procédure en C/C++ juste des fonctions– Le début est la fin d'une fonction est indiquée par une

accolade ouvrante {  et une accolade fermante } respectivement

– Les paramètres d'une fonction sont définies après le nom de la fonction, entre parenthèses

Page 107: Introduction à C++

Introduction à la programmation objet et générique avec C++ 107

Généralités sur le C++ (8) : un « meilleur C » Généralités sur le C++ (8) : un « meilleur C » ✔ Déclaration des variables

– En C et en C++, il faut déclarer une variables avant son initialisation.

– Pour déclarer une variable, il faut indiquer son type et son nom

• <type_variable> <nom_variable>; • int i;

– On peut avoir une déclaration de plusieurs variables d'un même type :

• Plutôt que d'avoir– int i; – int j; – int k;

• On pourrait avoir – int i, j ,k;

Page 108: Introduction à C++

Introduction à la programmation objet et générique avec C++ 108

Généralités sur le C++ (9) : un « meilleur C » Généralités sur le C++ (9) : un « meilleur C » ✔ Déclaration des variables (suite)

– L'affectation d'un valeur à une variable se fait avec =• i = 10 ;

– On peut déclarer et initialiser une varaible en même temps• int i = 10;

– Lieu des déclarations des variables• En C, les déclarations de variables doivent apparaître en

début de bloc.• En ANSI C99 et en C++, on peut déclarer les variables où

l'on veut (ou presque).– Cela nous permettra en C++ de déclarer nos variables

au moment ou nous en avons besoin et de les initialiser directement.

Page 109: Introduction à C++

Introduction à la programmation objet et générique avec C++ 109

Généralités sur le C++ (10) : un « meilleur C »Généralités sur le C++ (10) : un « meilleur C »

#include <cstdlib>#include <iostream>using namespace std;

int main (){ cout << "entrer un premier nombre" << endl; double a; cin >> a; cout << "entrer un deuxième nombre" << endl; double b; cin >> b; double nombre; nombre = a+b; cout << "La somme des 2 nombres est : " << nombre << endl; system("PAUSE"); return 0;}

✔ Déclaration des variables : exemple– Un troisième programme

Page 110: Introduction à C++

Introduction à la programmation objet et générique avec C++ 110

Généralités sur le C++ (11) : un « meilleur C »Généralités sur le C++ (11) : un « meilleur C »✔ Opérateurs arithmétiques

– En langage C++, nous retrouvons les opérateurs arithmétiques classiques du C

• +, -, * : addition, soustraction, multiplication• / :

– division « classique » entre 2 nombres réels ou entre un nombre réels et un entier

– division euclidienne entre 2 entiers --> donne le quotient par la division euclidienne

• % : opérateur « modulo » --> correspond au reste par la division euclidienne

– 5 / 3 == 1– 5 % 3 == 2

▪ 5 = 1 * 3 + 2

quotient reste

Page 111: Introduction à C++

Introduction à la programmation objet et générique avec C++ 111

Généralités sur le C++ (12) : un « meilleur C »Généralités sur le C++ (12) : un « meilleur C »

#include <cstdlib>#include <iostream>using namespace std;

int main (){ cout << "entrer un premier nombre" << endl; int a, b; cin >> a; do { cout << "entrer un deuxième nombre plus petit " << endl; cin >> b; } while(b > a); int quotient = a / b; int reste = a % b; cout << a << "=" << b << "*" << quotient << "+" << reste << endl ; system("PAUSE"); return 0;}

✔ Opérateurs arithmétiques : exemple

Page 112: Introduction à C++

Introduction à la programmation objet et générique avec C++ 112

Généralités sur le C++ (13) : un « meilleur C »Généralités sur le C++ (13) : un « meilleur C »✔ En langage C, il existe différents opérateurs

– Opérateurs binaires de comparaison : <, > , <=, >=, !=– Opérateurs logiques : &&, ||, !– Opérateurs bits à bits : &, |– Opérateur ternaire : ? :

✔ En C++, ces opérateur restent valables, ainsi que beaucoup d'autre– De manière générale tous les opérateurs du C existent en

C++.– C++ introduit de nouveaux opérateurs comme new, delete

ou :: par exemple.• Nous les verrons au fur et à mesure du cours

– Nous verrons également que C++ permet de redéfinir les opérateurs pour les nouveaux types de données définis par l'utilisateur.

Page 113: Introduction à C++

Introduction à la programmation objet et générique avec C++ 113

Généralités sur le C++ (14) : un « meilleur C »Généralités sur le C++ (14) : un « meilleur C »✔ Ecriture d'information sur la sortie standard

– La fonction printf est toujours utilisable• Il faut simplement faire un #include <cstdio> pour l'inclure

dans un fichier C++• Néanmoins nous avons maintenant à notre disposition un

outil un peu plus souple avec l'arrivée de nouvelles fonctionnalités propres au C++ dans sa bibliothèque standard.

#include <cstdlib>#include <cstdio> using namespace std;

int main (){ printf("La programmation avec C++, c'est trop fou!!!\n"); system("PAUSE"); return 0;}

Page 114: Introduction à C++

Introduction à la programmation objet et générique avec C++ 114

Généralités sur le C++ (15) : un « meilleur C »Généralités sur le C++ (15) : un « meilleur C »✔ La bibliothèque standard du C++

– La bibliothèque standard C++ regroupe un ensemble de fonctionnalités génériques potentiellement utilisables par tout programme.

• Il y a des fonctionnalités propres au C++, comme les flots d'entrées-sorties et la STL

• La bibliothèque standard du C++ reprend également l'intégralité de la bibliothèque standard du C

– Pour utiliser une fonctionnalité de cette bibliothèque, il suffit d'inclure le fichier d'en-tête correspondant.

• Les fichiers d'en-tête de la bibliothèque standard C++ ne possède pas d'extension .h afin d'éviter des problèmes de compatibilité avec les anciens version en .h des fichiers d'en-tête avant leur standardisation.

– La bibliothèque standard C++ propose des fonctionnalités pour la manipulation de diagnostics, d'utilitaires d'ordre général, de chaînes de caractères, d'éléments de localisation, de conteneurs, d'éléments d'itération, d'algorithmes, de nombres et des flots d'entrées-sorties.

Page 115: Introduction à C++

Introduction à la programmation objet et générique avec C++ 115

Généralités sur le C++ (16) : un « meilleur C »Généralités sur le C++ (16) : un « meilleur C »✔ L'espace de nom std

– Les fichiers d'en-tête sans extension .h placent leur contenu dans l'espace de nom std

• Toujours pour éviter des conflits avec les versions antérieures des biblitohèques

– Cela implique donc de « qualifier » cet espace de noms pour utiliser les fonctionnalités standard soit directement en utilisant l'opérateur de résolution de portée ::, soit en utilisant la directive using.

#include <cstdlib>#include <iostream>

int main (){ std::cout << "essai" << std::endl; system("PAUSE"); return 0;}

#include <cstdlib>#include <iostream>using namespace std;

int main (){ cout << "essai" << endl; system("PAUSE"); return 0;}

Page 116: Introduction à C++

Introduction à la programmation objet et générique avec C++ 116

Généralités sur le C++ (17) : un « meilleur C »Généralités sur le C++ (17) : un « meilleur C »✔ Support de la bibliothèque standard C

– En fait la bibliothèque standard du C++ contient sa propre version des fichiers en-tête standard du C

– Le nom de ces fichiers en-tête est semblable à celui proposé dans la bibliothèque standard C

• Cependant ils n'ont pas d'extension .h et ils sont préfixés par le caractère « c »

– #include <cstdlib> ou #include <cstdio>• Encore une fois l'espace de nom std est utilisé pour

différencier ces fonctinnalités de celles fournies dans les fichiers en-tête de la biblitothèque standard C.

Page 117: Introduction à C++

Introduction à la programmation objet et générique avec C++ 117

Généralités sur le C++ (18) : un « meilleur C »Généralités sur le C++ (18) : un « meilleur C »✔ Flots d'entrées-sorties

– Les flots d'entrées-sorties sont le moyen privilégiés d'effectuer des opérations d'entrées-sorties avec les périphériques standard et les fichiers en C++.

– Quatre flots sont prédéfinis pour les périphériques standards d'entrées-sorties

• cin• cout • cerr • clog

– L'élément endl est également défini • Il ajoute un retour à la ligne dans les flots en sortie

Page 118: Introduction à C++

Introduction à la programmation objet et générique avec C++ 118

Généralités sur le C++ (19) : un « meilleur C »Généralités sur le C++ (19) : un « meilleur C »✔ Flots d'entrées-sorties : cin

– Nous allons pouvoir utiliser cin à la place du scanf – L'objet cin contrôle l'entrée reçue depuis le tampon associé

au flot C stdin.• Pour utiliser cet objet il suffit d'inclure le fichier en-tête <iostream>.

• Attention cin est un objet!– Son type (sa classe) est istream.– La classe istream redéfinit l'opérateur >>

• L'opérateur >> effectue normalement un décalage de bits vers la droite

• Utilisé avec cin, il est redéfini pour pouvoir lire les types de données prédéfinis depuis le flot d'entrée

– On peut redéfinir l'opérateur >> pour pouvoir lire directement des objets issus d'un des types de données (classe) utilisateur

– On peut enchainer les opérations d'entrée.

Page 119: Introduction à C++

Introduction à la programmation objet et générique avec C++ 119

Généralités sur le C++ (20) : un « meilleur C »Généralités sur le C++ (20) : un « meilleur C »

#include <cstdlib>#include <iostream>using namespace std;

int main (){ cout << "entrer 2 nombres entiers" << endl; int a, b,temp, quotient, reste; cin >> a >> b;

if (a < b) { temp = a; a = b; b = temp; } quotient = a / b; reste = a % b; cout << a << "=" << b << "*" << quotient << "+" << reste << endl ; system("PAUSE"); return 0;}

✔ Flots d'entrées-sorties : cin - exemple

Page 120: Introduction à C++

Introduction à la programmation objet et générique avec C++ 120

Généralités sur le C++ (21) : un « meilleur C »Généralités sur le C++ (21) : un « meilleur C »✔ Flots d'entrées-sorties : cin versus scanf

– Tout comme la fonction printf, la fonction scanf est toujours utilisable

• Il faut simplement faire un #include <cstdio> pour l'inclure dans un fichier C++

• Néanmoins, cin offre un peu plus de souplesse – Rappel (just in case) : scanf permet de récupérer une valeur

saisie sur l'entrée standard– scanf("%<type_à_récupérer>", <pointeur_sur_type_à_récupérer>);

– Si s est un char * (un pointeur sur caractère)• scanf("%s", s); // pour récupérer une chaine

– Si a est une variable entière• scanf("%d", &a); // pour récupérer un entier

– Si a est un réel double précision• scanf("%lf",&a); // pour récupérer un réel de type double

• Attention « scanf » attend une variable de type pointeur

Page 121: Introduction à C++

Introduction à la programmation objet et générique avec C++ 121

Généralités sur le C++ (22) : un « meilleur C »Généralités sur le C++ (22) : un « meilleur C »

#include <cstdlib>#include <cstdio>using namespace std;

int main (){ printf("Entrer une chaine de caracteres\n"); char s[50]; scanf("%s",s); printf("j'affiche une chaine de caracteres\n%s\n", s); printf("Entrer un entier\n"); int a; scanf("%d",&a); printf("puis j'affiche un entier (%d)\n", a); printf("Entrer un reel\n"); double b; scanf("%lf",&b); printf("et un reel (%f) \n", b); system("PAUSE"); return 0;}

✔ Flots d'entrées-sorties : scanf - exemple

Page 122: Introduction à C++

Introduction à la programmation objet et générique avec C++ 122

Généralités sur le C++ (23) : un « meilleur C »Généralités sur le C++ (23) : un « meilleur C »✔ Flots d'entrées-sorties : cout

– Nous allons pouvoir utiliser cout à la place du printf– L'objet cout contrôle la sortie envoyée vers un tampon

associé au flot C stdout.• Pour utiliser cet objet il suffit d'inclure le fichier en-tête <iostream>.

• Attention cout est un objet!– Son type (sa classe) est ostream.– La classe ostream redéfinit l'opérateur <<

• L'opérateur << effectue normalement un décalage de bits vers la gauche

• Utilisé avec cout, il est redéfini pour pouvoir écrire les types de données prédéfinis dans le flot de sortie

– On peut redéfinir l'opérateur << pour pouvoir écrire directement des objets issus d'un des types de données (classe) utilisateur

– On peut enchaîner les opérations de sortie.

Page 123: Introduction à C++

Introduction à la programmation objet et générique avec C++ 123

Généralités sur le C++ (24) : un « meilleur C »Généralités sur le C++ (24) : un « meilleur C »✔ Flots d'entrées-sorties : cerr et clog

– Les objets cerr et clog contrôle la sortie envoyée vers un tampon associé au flot C stderr.

• Pour utiliser ces objets il suffit d'inclure le fichier en-tête <iostream>.

• Attention cerr et clog ont un fonctionnement similaire à l'objet cout.

– Par rapport à cerr, clog est une sortie bufferisée.✔ Remarque sur les flots d'entrée et de sortie

– Les objets cin et cout permettent également de remplacer avantageusement getchar et putchar, qui sont toujours par ailleurs utilisables, tout comme printf et scanf.

Page 124: Introduction à C++

Introduction à la programmation objet et générique avec C++ 124

Généralités sur le C++ (25) : un « meilleur C »Généralités sur le C++ (25) : un « meilleur C »✔ Exercice

– Proposez un petit programme C++, avec juste une fonction main permettant à un utilisateur de saisir la largeur et la longueur d'un rectangle, et qui renvoie le périmètre et l'aire de ce rectangle.

Page 125: Introduction à C++

Introduction à la programmation objet et générique avec C++ 125

Généralités sur le C++ (26) : un « meilleur C »Généralités sur le C++ (26) : un « meilleur C »✔ Exercice : correction

– Proposez un petit programme C++, avec juste une fonction main permettant à un utilisateur de saisir la largeur et la longueur d'un rectangle, et qui renvoie le périmètre et l'aire de ce rectangle.

#include <cstdlib>#include <iostream>using namespace std;

int main (){ double longueur, largeur, aire, perimetre; cout << "Entrer la longueur de votre rectangle" << endl; cin >> longueur; cout << "Entrer la largueur de votre rectangle" << endl; cin >> largeur; aire = largeur * longueur; perimetre = largeur * 2 + longueur * 2; cout << "la surface : " << aire << " ; le perimètre : " << perimetre << endl; system("PAUSE"); return 0;}

Page 126: Introduction à C++

Introduction à la programmation objet et générique avec C++ 126

Généralités sur le C++ (27) : un « meilleur C »Généralités sur le C++ (27) : un « meilleur C »✔ Les fonctions en C et C++

– Une fonction en C/C++ peut renvoyer 0 ou 1 valeur.

Déclaration d'une fonction<type_renvoyé> <nom_fonction>(<param1>, <param2>, ...);

Exempledouble surface(double largeur,double longueur);

Définition d'une fonction<type_renvoyé> <nom_fonction>(<param1>, <param2>, ...){ /* Corps de la fonction */}

Exempledouble surface(double largeur, double longueur){ return (largeur * longueur);}

Page 127: Introduction à C++

Introduction à la programmation objet et générique avec C++ 127

Généralités sur le C++ (28) : un « meilleur C »Généralités sur le C++ (28) : un « meilleur C »

#include <cstdlib>#include <iostream>using namespace std;

double surface (double largeur,double longueur);double perimetre (double largeur, double longueur);

int main (){ double longueur, largeur, aire, peri; cout << "Entrer la longueur de votre rectangle" << endl; cin >> longueur; cout << "Entrer la largueur de votre rectangle" << endl; cin >> largeur; aire = surface(largeur,longueur); peri = perimetre(largeur,longueur); cout << "la surface : " << aire << " ; le perimètre : " << peri << endl; system("PAUSE"); return 0;}

double surface(double largeur, double longueur){ return (largeur * longueur); }

double perimetre (double largeur, double longueur){ return (largeur * 2 + longueur * 2); }

✔ Les fonctions en C et C++ : exemple

Page 128: Introduction à C++

Introduction à la programmation objet et générique avec C++ 128

Généralités sur le C++ (29) : un « meilleur C »Généralités sur le C++ (29) : un « meilleur C »

if (condition vraie) {

séquence d'instructions 1

}else{

séquence d'instructions 2

}

Clause SINON/else facultative

Bloc d'instructions 1

Bloc d'instructions 2

✔ Les alternatives en C/C++

Page 129: Introduction à C++

Introduction à la programmation objet et générique avec C++ 129

Généralités sur le C++ (30) : un « meilleur C »Généralités sur le C++ (30) : un « meilleur C »

condition

vraie (alors)

Série 1 d’actions

Série 2 d’actions

fausse (sinon)

if (condition vraie) {

série d'actions 1 }else {

série d'actions 2

}

✔ Les alternatives en C/C++ (suite)

Page 130: Introduction à C++

Introduction à la programmation objet et générique avec C++ 130

Généralités sur le C++ (31) : un « meilleur C »Généralités sur le C++ (31) : un « meilleur C »✔ Les alternatives en C/C++ : expression booléenne

– La condition du if• La condition exprimée entre parenthèses à la suite du if

doit être une expression booléenne simple ou composée– Des expressions booléennes

• A != 0 //différent de – not equal• B == 3 // égalité• C >= 5 // supérieur ou égale• (A <= 4) || (A >= 6) /

• Nous avons un ensemble d'opérateurs de comparaisons renvoyant une valeur booléenne

– !=, ==, <, >, <=, >=

Page 131: Introduction à C++

Introduction à la programmation objet et générique avec C++ 131

Généralités sur le C++ (32) : un « meilleur C »Généralités sur le C++ (32) : un « meilleur C »✔ Les alternatives en C/C++ : expression booléenne

– Opérateurs booléens• Nous avons en langage C/C++ les opérateurs booléens

courants qui nous permettent de créer des expressions booléennes complexes

– || : le « ou » logique (disjonction) ; opérateur binaire– && : le « et » logique (conjonction) ; opérateur binaire– ! : la négation logique ; opérateur unaire

• Rappel : il existe également des opérateurs bits à bits– | : le « ou » bit à bit– & : le « et » bit à bit

Page 132: Introduction à C++

Introduction à la programmation objet et générique avec C++ 132

Généralités sur le C++ (33) : un « meilleur C »Généralités sur le C++ (33) : un « meilleur C »✔ Le type booléen

– S'il n'existe pas de type booléen en C, il en existe un en C++– En C (rappel)

• Par définition une expression arithmétique ou logique vaut 1 si la relation est vraie et 0 si elle est fausse

• L'opérateur unaire de négation, « ! », donne la valeur zéro si son opérande est non-nul et 1 s'il est nul.

• La valeur entière 0 peut être assimilée à la valeur booléenne FAUX en C et 1 peut-être assimilée à la valeur booléenne VRAI

Page 133: Introduction à C++

Introduction à la programmation objet et générique avec C++ 133

Généralités sur le C++ (34) : un « meilleur C »Généralités sur le C++ (34) : un « meilleur C »✔ Le type booléen en C++

– En C++• Les booléens sont de type bool et représentent les

valeurs vrai ou faux– Le type bool est un des types entiers (avec les types

correspondants aux caractères et ceux correspondants aux entiers).

• Les booléens n'ont que 2 valeurs possibles : true et false

– La taille d'un bool est d'1 octet en général– Les seuls littéraux booléens sont les mots-clés true

et false– Par convention

• false a pour valeur 0 • Toute autre valeur est considérée comme true

Page 134: Introduction à C++

Introduction à la programmation objet et générique avec C++ 134

Généralités sur le C++ (35) : un « meilleur C »Généralités sur le C++ (35) : un « meilleur C »

TANTQUE(condition vraie)FAIRE

séquence d'instructionsFINFAIRE

while(condition_vraie){ /* séquence d'instructions */}

conditioncondition

vraie

Instructions

fausse

✔ Les itératives en C et C++ : while

Page 135: Introduction à C++

Introduction à la programmation objet et générique avec C++ 135

Généralités sur le C++ (36) : un « meilleur C »Généralités sur le C++ (36) : un « meilleur C »✔ Les itératives en C et C++ : condition de boucle

– Comme pour le if, la condition que l'on teste pour entrer ou non dans la boucle est une expression booléenne

• Donc s'évaluant à quelque chose du type bool en C++– Rappel :

• en général cette condition est constituée d'une ou plusieurs variables de boucles.

– Avant d'entrée dans la boucle il faut s'assurer que l'initialisation de la ou des variables de boucles a été correctement effectuée.

– De même, si on veut sortir de la boucle a un moment ou à un autre, il faut que certaines instructions à l'intérieur du bloc de la boucle, fasse évoluer la valeur des variables de la condition (et donc fassent évoluer la valeur de vérité de la condition).

Page 136: Introduction à C++

Introduction à la programmation objet et générique avec C++ 136

Généralités sur le C++ (37) : un « meilleur C »Généralités sur le C++ (37) : un « meilleur C »

do{ /* séquence d'instructions */}while(condition_vraie);

FAIREséquence d'instructions

TANTQUE (condition vraie)

conditionconditionvraie

Instructions

fausse

✔ Les itératives en C et C++ : do ... while

Page 137: Introduction à C++

Introduction à la programmation objet et générique avec C++ 137

Généralités sur le C++ (38) : un « meilleur C »Généralités sur le C++ (38) : un « meilleur C »

for(<init_cond>;<test_cond>;<maj_cond>){ /* séquence d'instructions */}

<init_cond>while(<test_cond>){ /* séquence d'instructions */ <maj_cond>;}

condition<test_cond>

vraie

Instructions

fausse

<init_cond>

<maj_cond>

✔ Les itératives en C et C++ : boucle for

Page 138: Introduction à C++

Introduction à la programmation objet et générique avec C++ 138

Généralités sur le C++ (39) : un « meilleur C »Généralités sur le C++ (39) : un « meilleur C »✔ Incrémentation et décrémentation

– L'opérateur ++• L'opérateur ++ est un opérateur unaire qui ajoute 1 à son

opérande• i++ est équivalent à i = i +1

– L'opérateur --• L'opérateur -- est un opérateur unaire qui enlève 1 à son

opérande• i-- est équivalent à i = i -1

Page 139: Introduction à C++

Introduction à la programmation objet et générique avec C++ 139

Généralités sur le C++ (40) : un « meilleur C »Généralités sur le C++ (40) : un « meilleur C »✔ Incrémentation et décrémentation : préfixage et postfixage

– On peut ces 2 opérateurs de manières préfixées ou postfixées• Préfixées : ++n• Postfixées : n++

– Il y a une différence : dans les 2 cas la variable (n dans notre exemple) est incrémenté cependant

• ++n incrémente d'abord n avant d'évaluer la valeur de l'expression

• n++ incrémente n après avoir évalué l'expression– x = n++ ; /* on incrémente n après avoir mis sa valeur

dans x */• Si n valait 5 avant cette ligne, après n vaut 6 mais

x vaut 5– x = ++n ; /* on incrémente n puis on met sa valeur

dans x */• Si n valait 5 avant cette ligne, après n vaut 6 mais

x vaut 6 également

Page 140: Introduction à C++

Introduction à la programmation objet et générique avec C++ 140

Généralités sur le C++ (41) : un « meilleur C »Généralités sur le C++ (41) : un « meilleur C »✔ Alternative : switch ... case

– Le switch(expression) est une instruction de prise de décision à choix multiples

• Cette instruction permet de choisir une section de code à exécuter parmi celles qui suivent, selon la valeur d'une expression de contrôle

– Elle regarde si la valeur de expression fait partie d'un certains nombre de constantes entières

– Si il y a correspondance elle effectue le(s) traitement(s) associé(s) à la valeur.

switch(expression){ case expression-constante : instructions case expression_constante : instructions ... default : instructions}

Page 141: Introduction à C++

Introduction à la programmation objet et générique avec C++ 141

Généralités sur le C++ (42) : un « meilleur C »Généralités sur le C++ (42) : un « meilleur C »✔ Alternative : switch ... case (suite)

– Chaque section débute par le mot-clé case suivi d'une expression

• Cette expression doit renvoyer une valeur distincte, constante et entière lors de la compilation

• Lors de l'exécution, le flux saute à la section dont la valeur correspond à celle de l'expression de contrôle et continue l'exécution du programme à partir de ce point.

– Une instruction break peut être utilisée à la fin de la section afin de sortir du switch

• ainsi le code des sections suivantes n'est pas exécuté.

– Par défaut, si l'on n'est dans aucun des autres cas, l'exécution démarre au cas indiqué par default

• default est facultatif– Les différents case et default peuvent figurer dans un ordre

quelconque.

Page 142: Introduction à C++

Introduction à la programmation objet et générique avec C++ 142

Généralités sur le C++ (43) : un « meilleur C »Généralités sur le C++ (43) : un « meilleur C »✔ Alternative : switch ... case - exemple#include <cstdlib>#include <iostream>using namespace std;

int main (int argc, char *argv[]){

cout << "Entrer un chiffre entre 1 et 5 " << endl;int chiffre ;cin >> chiffre;switch(chiffre){

case 1 : cout << "Vous avez saisi le chiffre 1" << endl; break;

case 2 : cout << "Vous avez saisi le chiffre 2" << endl; break;

case 3 : cout << "Vous avez saisi le chiffre 3" << endl; break;

case 4 : cout << "Vous avez saisi le chiffre 4" << endl; break;

case 5 : cout << "Vous avez saisi le chiffre 5" << endl; break;

default : cout << "Vous n'avez pas suivi les consignes" << endl;}

system("PAUSE");}

Page 143: Introduction à C++

Introduction à la programmation objet et générique avec C++ 143

Généralités sur le C++ (44) : un « meilleur C »Généralités sur le C++ (44) : un « meilleur C »✔ Les fonctions mathématiques

– Nos retrouvons en C++ les fonctions mathématiques que nous avions en C

• Pour les utiliser il faut faire un #include <cmath>– Dans la liste suivante, x et y désignent des paramètres de

type double et n désigne un paramètre de type int.• Toutes les fonctions retournent un double• Les fonctions trigonométriques renvoient une valeur

exprimée en radians• Fonctions trigonométriques

– sin(x),cos(x), tan(x) : sinus, cosinus et tangente de x

– asin(x), acos(x), atan(x) : arc sinus, arc cosinus et arc tangente de x

– sinh(x), cosh(x), tanh(x) : sinux, cosinus et tangente hyperbolique de x

Page 144: Introduction à C++

Introduction à la programmation objet et générique avec C++ 144

Généralités sur le C++ (45) : un « meilleur C »Généralités sur le C++ (45) : un « meilleur C »✔ Les fonctions mathématiques (suite)

• Logarithme et exponentielle– exp(x) : exponentielle de x– log(x) : logarithme népérien de x (pour x >0)– log10(x) : logarithme à base 10 (pour x > 0)

• Arrondis– ceil(x) : le plus petit entier supérieur ou égal à x,

exprimé en double– floor(x) : le plus grand entier inférieur ou égal à x,

exprimé en double• Divers

– sqrt(x) : racine carrée de x (pour x > 0)– fabs(x) : valeur absolue de x

Page 145: Introduction à C++

Introduction à la programmation objet et générique avec C++ 145

Généralités sur le C++ (46) : un « meilleur C »Généralités sur le C++ (46) : un « meilleur C »✔ La génération de nombres aléatoires : La librairie <cstdlib>

– La librairie <cstdlib> comporte les fonctions associées à la génération de nombres (pseudo-)aléatoires

• int rand() : – retourne un entier pseudo-aléatoire entre 0 et RAND_MAX.

– RAND_MAX est une constante définie dans <cstdlib> qui vaut au minimum 32767

• void srand (unsigned int seed) – srand prend le paramètre seed comme amorce d'une

nouvelle séquence de nombre pseudo-aléatoire.– Il existe des bibliothèques non standards pour générer des

nombres pseudo-aléatoires ; par exemple :• C++ Hat Random Container

– http://home.comcast.net/~anglewyrm/hat.html – http://devpaks.org/files/hat.DevPak

• Newran02B - a random number generator library– http://www.robertnz.net/nr02doc.htm

Page 146: Introduction à C++

Introduction à la programmation objet et générique avec C++ 146

Généralités sur le C++ (47) : un « meilleur C »Généralités sur le C++ (47) : un « meilleur C »

#include <iostream>#include <cstdlib>#include <ctime>#include <cmath>using namespace std;

int main (int argc, char *argv[]){ srand((unsigned int)time((time_t *)NULL)); /* Initialisation du generateur*/ double r; int nombre; for (int i = 0 ; i < 10 ; i++) { r = rand()/(RAND_MAX +1.0); nombre = (int) ceil(rand()/(RAND_MAX +1.0) * 10); cout << "un nombre " << (i+1) << "eme " << "réel aleatoire entre 0 et 1 (exclus) : " << r << endl; cout << "un nombre entier aléatoire entre 1 et 10 : " << nombre << endl; } system("PAUSE"); return 0;}

Sous Linux/Unix, ne pas oublier de lier les bibliothèques mathématiques explicitement lors de la compilation

✔ La génération de nombres aléatoires : exemple

Page 147: Introduction à C++

Introduction à la programmation objet et générique avec C++ 147

Généralités sur le C++ (47) : un « meilleur C »Généralités sur le C++ (47) : un « meilleur C »✔ Transtypage == coercition de type == forçage de type

– En C, le programmeur dispose d'un opérateur unaire lui permettant de forcer une conversion d'un type dans un autre

• On parle d'opérateur de coercition - On parle de « cast » en Anglais

– (nom_type)expression;• (double) i / 3;

– Le « cast » est toujours possible en C++ avec les risques que cela comporte (aucun contrôle n'est effectué à l'exécution pour vérifier la légitimité de cette conversion).

• La conversion est possible dans les cas suivants– Conversion d'un pointeur ou d'un type arithmétique en

type entier– Conversion d'un type arithmétique en type à virgule

flottante– Conversion d'un pointeur ou d'un type arithmétique en

un autre type pointeur– Il existe d'autres possibilités de conversion en C++

Page 148: Introduction à C++

Introduction à la programmation objet et générique avec C++ 148

Généralités sur le C++ (48) : un « meilleur C »Généralités sur le C++ (48) : un « meilleur C »✔ Les types fondamentaux

– On retrouve les types du C et des nouveaux types• Les types arithmétiques

– Les types entiers : booléens, caractères et entiers• bool, char, wchar_t, short, int, long

– Les nombres à virgules flottantes• float, double, long double

• Le type void

Page 149: Introduction à C++

Introduction à la programmation objet et générique avec C++ 149

Généralités sur le C++ (49) : un « meilleur C »Généralités sur le C++ (49) : un « meilleur C »✔ Les types fondamentaux : booléens

– Le type bool• Les booléens n'ont que 2 valeurs possibles : true et false

– Les seuls littéraux booléens sont les mots-clés trueet false

– Par convention• false a pour valeur 0 • Toute autre valeur est considérée comme true

Page 150: Introduction à C++

Introduction à la programmation objet et générique avec C++ 150

Généralités sur le C++ (50) : un « meilleur C »Généralités sur le C++ (50) : un « meilleur C »✔ Les types fondamentaux : caractères

– Les types char et wchar_t• Le type char sert à stocker des entiers qui correspondent

à des valeurs d'un jeu de caractères donné (l'ASCII en général).

• Le type wchar_t permet de stocker des valeurs suffisamment grandes pour représenter les jeux de caractères de toutes les localisations supportées par l'implémentation donnée du C++

• Pour utiliser les fonctionnalités du type wchar_t il faut inclure le fichier en-tête <cwchar>

• Les constantes caractère sont entourées d'apostrophes– char c = 'A';

• Pour spécifier des constantes caractère de type « large », il faut les précéder d'un « L »

– wchar_t c = L 'A';– Pour la liste des caractères ASCII voir par exemple

• http://big.chez.com/cosmos2000/Nombres/ASCII.html

Page 151: Introduction à C++

Introduction à la programmation objet et générique avec C++ 151

Généralités sur le C++ (51) : un « meilleur C »Généralités sur le C++ (51) : un « meilleur C »✔ Les types fondamentaux : entiers

– Les types short, int et long• Ces types différent par leur taille de stockage et donc par

la plage de valeur qu'ils peuvent représenter• Les entiers peuvent être signés ou non avec signed ou unsigned. Par défaut, si on ne précise rien, ils sont signés

– signed short entier_court_signe;– unsigned int entier_non_signe;

• La plage de valeurs que ces types peuvent représenter est définie dans le fichier en-tête standard <climits>

Page 152: Introduction à C++

Introduction à la programmation objet et générique avec C++ 152

Généralités sur le C++ (51) : un « meilleur C »Généralités sur le C++ (51) : un « meilleur C »✔ Les types fondamentaux : les flottants

– Les types float, double et long float• Ces types représentent les nombres à virgule flottante• Ces types différent par leur taille de stockage et donc par

la plage de valeur qu'ils peuvent représenter• La plage de valeurs que ces types peuvent représenter est

définie dans le fichier en-tête standard <cfloat>• Le séparateur décimal en C++ est le « . »• On peut saisir les littéraux flottants sous forme classique

ou sous forme scientifique– double val_1 = 45.78;– double val_2 = 3.6e+12;

Page 153: Introduction à C++

Introduction à la programmation objet et générique avec C++ 153

Généralités sur le C++ (52) : un « meilleur C »Généralités sur le C++ (52) : un « meilleur C »✔ Les types fondamentaux : le type void

– Le type void• Ce type indique l'absence de valeur

– Il est couramment utilisé pour déclarer des fonctions sans valeur de retour.

• Il permet aussi de déclarer un pointeur sur tout type de donnée

– Seules les variables qui sont des pointeurs peuvent être déclarées de type void.

Page 154: Introduction à C++

Introduction à la programmation objet et générique avec C++ 154

Généralités sur le C++ (53) : un « meilleur C »Généralités sur le C++ (53) : un « meilleur C »✔ Les constantes énumérées

– En C et C++ on peut définir avec le mot-clé enum un ensemble de valeurs constantes entières associées une à une à des identifiants, ou énumérateurs.

– Les énumérations peuvent être utilisées pour définir des constantes entières avec un nom significatif

• Elles remplacent avantageusement les constantes défines avec des #define

• L'un des intérêts est de pouvoir bénéficier des règles de portées du C++, ce qui n'est pas le cas avec les directives au préprocesseur

– enum <nom_enum> { <liste_constante>};• enum jour {LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE};

– Le nom de lénumération n'est pas obligatoire mais il permet de définir des variables pouvant contenir des valeurs de l'énumération.

Page 155: Introduction à C++

Introduction à la programmation objet et générique avec C++ 155

Généralités sur le C++ (54) : un « meilleur C »Généralités sur le C++ (54) : un « meilleur C »✔ Les constantes énumérées (suite)

– La première constante définie vaut par défaut 0, puis la seconde 1, etc. si on ne précise rien. Sinon les valeurs se déduisent de la première valeur spécifiée par incréments successifs

• enum jour {LUNDI = 1, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE};

– LUNDI vaut 1, MARDI vaut 2, MERCREDI aut 3, etc.– Les énumérateurs associés aux valeurs entières de

l'énumération peuvent être utilisés en lieu et place de constante entière

– Il est normalement possible d'utiliser un énumérateur partout où un int peut l'être.

– Il n'est pas possible d'affecter n'importe quel entier à une variable de type énumération

– Par défaut la taille des entiers affectés aux énumérateurs est inférieure ou égale à celle d'un int, sauf si un entier plus grand est défini explicitement.

Page 156: Introduction à C++

Introduction à la programmation objet et générique avec C++ 156

Généralités sur le C++ (55) : un « meilleur C »Généralités sur le C++ (55) : un « meilleur C »✔ Rappel : les tableaux unidimensionnel

– Un tableau « unidimensionnel » correspond à l'idée de vecteur en mathématique

• Un tableau peut contenir plusieurs valeurs d'un même type en même temps

– Un tableau a une taille qui correspond au nombre de valeurs que peut contenir le tableau

– Un tableau est un ensemble d'éléments indexés• On accède aux différentes valeurs stockées dans le

tableau par l'indice (c'est-à-dire la position) de cet élément dans le tableau.

1er élément

1 2 3 4 5 6

Dernier élément

Une case du tableauLe contenu de la case

Page 157: Introduction à C++

Introduction à la programmation objet et générique avec C++ 157

Généralités sur le C++ (56) : un « meilleur C »Généralités sur le C++ (56) : un « meilleur C »✔ Déclaration d'une variable tableau en C et C++

– Pour définir une variable ou un paramètre de type tableau• <type_elem_tab> <nom_tab>[<taille_tab>];

– <type_elem_tab> est à remplacer par un type de données (int, double, char, float, etc.)

• Il définit le type des éléments que peut contenir le tableau

– <nom_tab> est le nom de votre variable tableau – <taille_tab> est à remplacer par une valeur entière et

correspond à la taille de notre tableau.– Le nombre d 'éléments du tableau et le type de ces éléments

doivent être spécifiés lors de la définition du tableau afin que le compilateur puisse réserver la taille mémoire nécessaire pour stocker ce tableau.

Page 158: Introduction à C++

Introduction à la programmation objet et générique avec C++ 158

Généralités sur le C++ (57) : un « meilleur C »Généralités sur le C++ (57) : un « meilleur C »✔ Utilisation d'une variable de type tableau

– Une variable de type tableau sert à représenter un ensemble d'éléments identiques

• L'intérêt est de pouvoir accéder aux différents éléments qui sont dans le tableau

– On peut y accéder tant en lecture qu'en écriture : on lit des données stockées dans certaines case du tableau ou on écrit des données dans ces mêmes cases du tableau.

– On accède à un élément d'un tableau, en indiquant le nom du tableau suivi de l'indice de l'élément que l'on souhaite atteindre entre crochet

• Si on a un tableau tab, tab[3] me permet d'accèder au 3ème élément du tableau

– Attention en C les tableaux sont indicés à partir de 0• Un tableau de taille 10, verra ses indices aller de 0

à 9 !✔

Page 159: Introduction à C++

Introduction à la programmation objet et générique avec C++ 159

Généralités sur le C++ (58) : un « meilleur C »Généralités sur le C++ (58) : un « meilleur C »✔ Utilisation d'une variable de type tableau : exemple

– Si on a les déclarations de variables suivantes • int tab [10]; • int a ;

– On pourra écrire les expressions suivantes :– a = tab[1];

• j'accède à ce qui est contenu dans la deuxièmecase de mon tableau nommé tab et je l'affecte à la variable a.

– tab[0] = 4 ; • Je mets la valeur 4 dans la première case de mon

tableau tab (j'écrase la valeur qui y était éventuellement précédemment contenue)

✔ Taille du tableau et parcours du tableau– Bien faire attention à la taille du tableau

• Il ne faut pas essayer d'accéder à une case qui n'existe pas via un indice négatif ou plus grand que la taille du tableau.

Page 160: Introduction à C++

Introduction à la programmation objet et générique avec C++ 160

Généralités sur le C++ (59) : un « meilleur C »Généralités sur le C++ (59) : un « meilleur C »✔ Liste d'initialisation des tableaux

– On peut initialiser un tableau au moment de sa déclaration avec une liste de valeurs séparées par des virgules.

– Cette liste doit être entourée d'accolades « {  } »– Chacune des valeurs de la liste doit avoir un type compatible

avec celui déclaré pour les éléments du tableau• char *tab_jour[7] = {"lundi","mardi", "mercredi","jeudi","vendredi","samedi", "dimanche"};

– Lorsqu'une liste d'initialisation est donnée pour un tableau il n'est pas nécessaire préciser la taille de ce dernier.

• char *tab_jour[] = {"lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"};

– Si une taille est spécifiée et que la liste d'initialisation comprend moins d'éléments que cette taille, les éléments manquant seront initialisés par défaut (attention les résultats peuvent être surprenant).

Page 161: Introduction à C++

Introduction à la programmation objet et générique avec C++ 161

Généralités sur le C++ (60) : un « meilleur C »Généralités sur le C++ (60) : un « meilleur C »✔ Tableaux à plusieurs dimensions

– En C/C++ les tableaux à plusieurs dimensions sont des tableaux définis avec plusieurs index

– Déclaration pour 2 dimensions• <type_elt> <nom_tab> [<N>] [<M>]

– <type_elt> : type des éléments de mon tableau – <nom_tab> : nom de mon tableau

• <N> : valeur pour la première dimension de ma matrice (par exemple les lignes)

• <M> : valeur pour la deuxième dimension de ma matrice (par exemple les colonnes)

• double matrice [3][2];– Je définis par exemple une matrice qui a 3 lignes et 2

colonnes– On procédera de manière similaire pour des tableaux à plus

de 2 dimensions.✔

Page 162: Introduction à C++

Introduction à la programmation objet et générique avec C++ 162

Généralités sur le C++ (61) : un « meilleur C »Généralités sur le C++ (61) : un « meilleur C »✔ Déclaration et initialisation (exemple)

– <type_elt> <nom_tab> [<N>] [<M>] = { {...} {...}}

• double matrice [3][2] = { {1.0, 2.0}, {-1.0, 5.0}, {6.0, 7.0}};

✔ Accéder à un élement– Une fois le tableau multi-dimensionnelle définie, on accède à

un élément spécifique à l'aide de plusieurs index • Pour accéder à la troisième ligne et à la deuxième colonne

– int m = matrice [2][1]; // m vaut 7.0

Page 163: Introduction à C++

Introduction à la programmation objet et générique avec C++ 163

Généralités sur le C++ (62) : un « meilleur C »Généralités sur le C++ (62) : un « meilleur C »✔ Passage de tableaux aux fonctions

– Pour définir un argument tableau dans une fonction, il est obligatoire de définir toutes les dimensions du tableau, à l'exception de la première qui est facultative.

• Pour un tableau unidimensionnel, il n'est donc pas nécessaire de définir sa plage d'index.

• Pour un tableau bidimensionnel, la taille de la seconde dimension doit être spécifiée

– void f1(int tab_1[] {...}– double f2(double matrice[][15]) {...}

Page 164: Introduction à C++

Introduction à la programmation objet et générique avec C++ 164

Généralités sur le C++ (63) : un « meilleur C »Généralités sur le C++ (63) : un « meilleur C »✔ Chaînes et tableaux de caractères

– Les tableaux de caractères peuvent servir à représenter les chaînes de caractères en C++, tout comme en C

– Pour indiquer la fin d'une chaine de caractère nous avons comme en C, le caractère spéciale '\0' ;

• Bien faire attention que pour stocker une chaine de 10 caractères il faut un tableau de taille 11!

– Les fonctions renvoyant la taille d'une chaine comme strlen ne tiennent pas compte de ce caractère '\0'.

• Comme en C, en C++ on pourra utiliser des pointeurs pour représenter des chaines de caractères.

– En C++, on verra qu'il existe également une classe « string » (fichier en-tête <string> à ne pas confondre avec le fichier en-tête <cstring> !)

– Les littéraux chaînes doivent être entourés de guillemets• char nom[] = "toto";• Il est possible de découper un littéral en plusieurs chaînes

entourés de guillemets, éventuellement séparées d'espaces à des fins de présentation du code.

Page 165: Introduction à C++

Introduction à la programmation objet et générique avec C++ 165

Généralités sur le C++ (64) : un « meilleur C »Généralités sur le C++ (64) : un « meilleur C »✔ Fichier en-tête <cstring> : fonctions standards du C

– int strlen(char* s);• Retourne la longueur de la chaine s

– char* strcpy(char * dest, char *src);• Copie la chaine src dans la chaine dest

– int strlen(char* s);• Retourne la longueur de la chaine s, i.e. Le nombre e

caractères précédent le '\0' final.– char* strcpy(char * dest, char *src);

• Recopie la chaine src (avec le '\0') dans la chaine dest. Retourne également la chaine copiée.

– char* strncpy(char * dest, char *src, int n); • Effectue la même opération que strcpy mais en ne

recopiant au plus que n caractères– Si src a moins de n caractères, des '\0' sont ajoutés à

la fin de dest pour compléter.– Si src a plus de n caractères, aucun '\0' n'est

automatiquement ajouté à la fin de dest.

Page 166: Introduction à C++

Introduction à la programmation objet et générique avec C++ 166

Généralités sur le C++ (65) : un « meilleur C »Généralités sur le C++ (65) : un « meilleur C »✔ Fichier en-tête <cstring> : fonctions standards du C (suite)

– char* strcat(char * dest, char *src); • Contaténation de src à dest

– char* strncat(char * dest, char *src, int n); • Contaténation d'au plus n caractères de src à dest

– int strcmp(char * s1, char * s2);• Compare s1 et s2, retourne une valeur négative si s1

précède s2 (dans l'ordre alphabétique), une valeur nulle si les 2 chaines sont identiques et une valeur positive si s1suit s2.

– int strncmp(char * s1, char * s2, int n);• Même opération que strcmp sauf que seul les n premiers

caractères de chaque chaîne sont comparées.– Il y a d'autres fonctions dans cette bibliothèques

• strchr et strrchr pour trouver la première occurrence ou la dernière occurrence d'un caractère dans une chaîne, strstr pour trouver la première occurrence d'une chaine dans une autre chaine, etc.

Page 167: Introduction à C++

Introduction à la programmation objet et générique avec C++ 167

Généralités sur le C++ (66) : un « meilleur C »Généralités sur le C++ (66) : un « meilleur C »✔ Définition de type par l'utilisateur en C et C++

– Losrqu'un nom de type est trop long ou est difficile à manipuler, il est d'usage de définir un alias à l'aide du mot-clé typedef.

• Pour cela l'ancien nom de type et l'alias choisi doivent suivre le mot-lcé typedef

• typedef <definition_type> <nom_type>;– <definition_type> correspond au nom ou à la

définition de ce type– <nom_type> correspond au nouveau nom que vous

souhaitez donner à votre type– typedef unsigned long uint32;

Page 168: Introduction à C++

Introduction à la programmation objet et générique avec C++ 168

Généralités sur le C++ (66) : un « meilleur C »Généralités sur le C++ (66) : un « meilleur C »✔ Notion de pointeur

– Un pointeur est une variable qui contient l'adresse d'une autre variable

• un pointeur est une variable qui contient l'adresse d'une case mémoire

– Pour tout type T, on peut toujours définir un type pointeur vers T, pour des variables contenant l'adresse mémoire d'éléments de type T.

✔ Déclaration de pointeurs en C et en C++– Pour déclarer un pointeur, il suffit de placer un astérisque

« * » avant le nom de la variable correspondante.– <type> * <nom_var>;

• int * a;✔ Le pointeur NULL

– Nous avons une valeur par défaut pour indiquer que l'on « pointe dans le vide »

• NULL• a = NULL;

Page 169: Introduction à C++

Introduction à la programmation objet et générique avec C++ 169

Généralités sur le C++ (67) : un « meilleur C »Généralités sur le C++ (67) : un « meilleur C »✔ Accéder à l'adresse à laquelle se trouve une variable

– Opérateur unaire « & » (opérateur adresse)• Il renvoie l'adresse de la variable

– int i = 6; int *a = &i; ✔ Accéder aux objets pointés

– On parle de déréférencement de pointeur ou d'indirection• Cela revient à manipuler ce qui est pointé• Pour accéder au « contenu » d'un pointeur, on fait

précéder le pointeur d'un astérisque.– *<nom_var>;

• int *a; *a = 5;• int b = *a;• int c = 7;• a = &c;

Page 170: Introduction à C++

Introduction à la programmation objet et générique avec C++ 170

Généralités sur le C++ (68) : un « meilleur C »Généralités sur le C++ (68) : un « meilleur C »

char s[] = "toto";

s

0x00C9 0x07C9

int i = 5;

i

0x0FC9 0x0FCA 0x0FCB 0x0FCC

0x0FC9 't' 'o' 't' 'o' '\0'

0x0FCD

5

&i == 0x00C9; int *a = &i;

0x00C9

✔ Représentation en mémoire

Page 171: Introduction à C++

Introduction à la programmation objet et générique avec C++ 171

Généralités sur le C++ (68) : un « meilleur C »Généralités sur le C++ (68) : un « meilleur C »✔ Allouer et libérer de la mémoire pour un pointeur

– Pour allouer et libérer de l'espace mémoire correspondant à un pointeur, en C++ on utilisera plus les fonctions malloc et free

– Même si ces 2 fonctions sont toujours en principe utilisable, on utilisera les opérateurs new et new[] d'une part, deleteet delete[] d'autre part.

– L'opérateur new• T représente un type quelconque et n représente une

expression d'un type entier– l'expression new T[n] alloue l'emplacement

nécessaire pour n éléments du type T– Elle fournit en résultat un pointeur sur le type T (un « T * ») sur le premier élément.

• L'indication n est facultative : l'expression new T alloue l'emplacement pour un élément de type T et retourne un pointeur sur T (un « T * »).

– new T est équivalent à new T[1]

Page 172: Introduction à C++

Introduction à la programmation objet et générique avec C++ 172

Généralités sur le C++ (69) : un « meilleur C »Généralités sur le C++ (69) : un « meilleur C »✔ Allouer et libérer de la mémoire pour un pointeur : suite

– L'opérateur delete• Pour libérer un emplacement préalablement alloué par

new il faut utiliser l'opérateur delete– delete un_pointeur;

– L'opérateur delete[]• L'opérateur delete[] permet de libérer la mémoire

précédemment allouée à l'aide de new[].

Page 173: Introduction à C++

Introduction à la programmation objet et générique avec C++ 173

Généralités sur le C++ (70) : un « meilleur C »Généralités sur le C++ (70) : un « meilleur C »✔ Tableaux « dynamiques »

– De même qu'en C, on pouvait créer des tableaux dont la taille ne serait connue qu'au moment de l'exécution du programme, on pourra créer des tableaux alloués « dynamiquement » en C++. L'opération est même plus naturel

• On définit très simplement comme nous venons de le voir avec l'opérateur new le nombre d'éléments du type T dont on a besoin

• int * vecteur = new int[15];– Pour accéder aux éléments de notre variable vecteur, 2

manières équivalentes en C comme en C++• vecteur[i];• *(vecteur + i);

– Ne pas oublier de libérer vos pointeurs et tableaux dynamiques après utilisation avec l'opérateur delete.

Page 174: Introduction à C++

Introduction à la programmation objet et générique avec C++ 174

Généralités sur le C++ (70) : un « meilleur C »Généralités sur le C++ (70) : un « meilleur C »✔ Tableaux « dynamiques » : tableaux à plusieurs dimensions

– Pour une matrice par exempledont la taille n'est connu au moment de la compilation, on adoptera une manière de procéder similaire au C

• On passe par l'utilisation d'un pointeur dont on va allouer la taille

• matrice = new int[LIGNE*COLONNE];– Pour accéder aux éléments de notre variable matrice, une

manière de procéder sera la suivante• *(matrice + i * COLONNE + j)

– Voir le petit programme d'exemple essai_matrice.cpp sous /home/Informations/Enseignements/LangageCpp/Exemples/Exemples_du_Cours_1

Page 175: Introduction à C++

Introduction à la programmation objet et générique avec C++ 175

Généralités sur le C++ (72) : un « meilleur C »Généralités sur le C++ (72) : un « meilleur C »✔ Les pointeurs génériques : pointeurs sur void

– En C++ on peut toujours définir des pointeurs génériques– void * : correspond au type pointeur générique.

• En C, en déclarant une variable ou un paramètre comme étant un void *, on pourra affecter à cette variable ou associer à ce paramètre n'importe quel type de pointeur.

– En C++, un pointeur de type void * ne peut pas être converti implicitement lors d'une affectation en un pointeur d'un autre type. Il faudra faire un « cast explicite ».

• L'opération inverse, c'est-à-dire affecter un « résultat » « void * » dans une variable d'un autre type de pointeur est possible en C et en C++ moyennant un « cast » :

– il faut convertir le « void * » dans le bon type de pointeur

• Implique de savoir ce qu'on fait et à quel type correspond réellement le contenu de la variable pointée par le void * pour faire un « cast » correct.

Page 176: Introduction à C++

Introduction à la programmation objet et générique avec C++ 176

Généralités sur le C++ (73) : un « meilleur C »Généralités sur le C++ (73) : un « meilleur C »•Quelques différences C/C++ (1)

– Les macros ne sont normalement plus nécessaires en C++• Il faut utilisez les « const » ou les « enum » pour définir

des constantes manifestes• « inline » pour éviter le coût d'un appel de fonction• « template » pour spécifier une famille de fonctions et de

types– Déclaration des variables

• Ne déclarez pas une variable avant d'en avoir besoin, vous pourrez ainsi l'initialiser immédiatement

– En C++ une déclaration peut figurer partout où peut figurer une instruction.

– Attention par contre à la portée de vos variables

Page 177: Introduction à C++

Introduction à la programmation objet et générique avec C++ 177

Généralités sur le C++ (74) : un « meilleur C »Généralités sur le C++ (74) : un « meilleur C »•Quelques différences C/C++ (2)

– Allocation mémoire• N'utilisez plus malloc(), l'opérateur new fait le même

travail en mieux– A éviter

• Essayer d'éviter les void*, l'arithmétique sur les pointeurs, les tableaux C et la conversion de type explicite, sauf en plein coeur de la mise en oeuvre de certaines fonctions ou classes.

Page 178: Introduction à C++

Introduction à la programmation objet et générique avec C++ 178

Généralités sur le C++ (75) : un « meilleur C »Généralités sur le C++ (75) : un « meilleur C »•Notion de référence

– Une référence permet de définir un alias sur une variable (ou un objet)

• Pour déclarer une référence , on place le symbole esperluette (le et commercial « & ») avant le nom de la variable correspondante.int i = 20;int &r = i; //r est une référence sur la variable i

• Une référence doit toujours être initialisée au moment de sa définition.

– En effet une référence doit toujours se référer à une variable

• Une fois initialisée, elle ne peut être modifiée pour se référer à autre chose

– Néanmoins, la variable associée peut être modifiée.• Les opérations appliquées à la référence le sont en fait sur

la variable ou l'objet concerné.– Une référence est une sorte de pointeur constant

Page 179: Introduction à C++

Introduction à la programmation objet et générique avec C++ 179

Généralités sur le C++ (76) : un « meilleur C »Généralités sur le C++ (76) : un « meilleur C »•Notion de référence : exempleint i = 20;int &r = i; //r est une référence sur la variable iint &s = i; //s est une référence sur la variable ir++;// i est incrémenté de 1s--; // i est décrémenté de 1

20

i

r s

Page 180: Introduction à C++

Introduction à la programmation objet et générique avec C++ 180

Généralités sur le C++ (77) : un « meilleur C »Généralités sur le C++ (77) : un « meilleur C »•Passage de paramètres par référence

– Il est courant d'utiliser des références dans les arguments de fonctions.

• Les modifications faites sur ces arguments dans le corps de la fonction sont donc répercutées sur les variables du code appelant

– Cela correspond à un « passage par adresse » ou en langage algorithmique le passage de paramètres en entrée et en sortie.

– La notion de référence est rarement utilisé en dehors du contexte de passage de paramètre.

– Pour déclarer une transmission par référence, on fait suivre du symbole esperluette (« & ») le type de l'argument dans l'en-tête de la fonction au moment de sa déclaration et de sa définition.

Page 181: Introduction à C++

Introduction à la programmation objet et générique avec C++ 181

Généralités sur le C++ (78) : un « meilleur C »Généralités sur le C++ (78) : un « meilleur C »•Passage de paramètres par référence : exemple

#include <iostream>#include <cstdlib>using namespace std;void swap(double &a, double &b);int main(){ double x,y; x = 1.0; y = 2.0; cout << "x = " << x << " ; y = " << y << endl; swap(x,y); cout << "x = " << x << " ; y = " << y << endl; system("PAUSE"); }void swap(double &a, double &b){ double temp = a; a = b; b = temp;}

Page 182: Introduction à C++

Introduction à la programmation objet et générique avec C++ 182

Généralités sur le C++ (79) : un « meilleur C »Généralités sur le C++ (79) : un « meilleur C »•Arguments par défaut

– Dans la déclaration d'une fonction, il est possible de prévoir pour un ou plusieurs arguments des valeurs par défaut

• Il faut obligatoirement que cela soient les derniers de la liste

• Ces valeurs par défaut sont indiquées par le signe « = » à la suite de l'argument

double fonction_1(char, int = 11, double = 11.5);double fonction_2(char c, int i = 11, double f = 11.5);

• Ces valeurs seront utilisés lors d'un appel de la fonction avec un nombre d'arguments inférieur à celui prévu.

Page 183: Introduction à C++

Introduction à la programmation objet et générique avec C++ 183

Généralités sur le C++ (80) : un « meilleur C »Généralités sur le C++ (80) : un « meilleur C »•Les fonctions en ligne

– Une fonction en ligne est une fonction dont les instructions sont incorporées dans le compilateur dans le module objet correspondant à chaque appel.

• On parle aussi de fonctions « développées »• Elles sont utilisées à des fins d'optimisation

– Cela évite en effet la perte de temps nécessaire à un appel usuel

• i.e. Le changement de contexte, la copie des valeurs des arguments sur la pile, etc.

– Par contre, les instructions de la fonction en ligne sont générées plusieurs fois

• Les fonctions en ligne offrent un intérêt similaire aux macros mais sans risque d'effet de bord.

– Une fonction en ligne est nécessairement définie en même temps qu'elle est déclarée (elle ne peut pas ête compilée séparément)

– Son en-tête est précédée du mot-clé inline• inline ma_fonction (...) { ... }

Page 184: Introduction à C++

Introduction à la programmation objet et générique avec C++ 184

Généralités sur le C++ (81) : un « meilleur C »Généralités sur le C++ (81) : un « meilleur C »•L'opérateur de séquence (rappel)

– La virgule (« , ») est l'opérateur de séquence• Elle permet d'évaluer 2 opérandes, de gauche à droite• La valeur d'une expression de séquence est le résultat du

dernier opérande• Exemple

for (i=0,j=10; i<10; i++,j--){

//incrémente i tout en décrémentant j}

Page 185: Introduction à C++

Introduction à la programmation objet et générique avec C++ 185

Généralités sur le C++ (82) : un « meilleur C »Généralités sur le C++ (82) : un « meilleur C »•Classe de stockage

– Les classes de stockage en C++ sont static, extern, mutable, auto et register

• La classe de stockage attribuée à une variable ou à un attribut de classe définit sa durée de vie et son type d'édition de liens

• La classe de stockage d'une fonction ou d'une méthode définit d'autres traitements.

Page 186: Introduction à C++

Introduction à la programmation objet et générique avec C++ 186

Généralités sur le C++ (83) : un « meilleur C »Généralités sur le C++ (83) : un « meilleur C »•Classe de stockage (suite)

– Dans le cas par défaut, quand on ne définit aucune classe de stockage explicitement, les règles suivantes s'appliquent :

• Variables locales– La classe de stockage par défaut est auto

• Variables globales– Elles ont une portée de fichier, sauf si elles sont

déclarées ailleurs avec le mot-clé extern• Membres de données (attributs)

– Il existe une instance distincte de chaque membre de données pour chaque instance de leur classe.

• Fonctions indépendantes de toute classe– La classe de stockage par défaut est extern

• Fonctions membres (méthodes)– Elles doivent être appelées sur une instance de leur

classe.

Page 187: Introduction à C++

Introduction à la programmation objet et générique avec C++ 187

Généralités sur le C++ (84) : un « meilleur C »Généralités sur le C++ (84) : un « meilleur C »•Classe de stockage : static

– La classe de stockage static a pour signification dans les cas suivants

• Variables locales– Leur valeur est conservée entre 2 appels du bloc les

contenant– Elles ne sont donc construites qu'une seule fois ou

jamais si le code de leur déclaration n'est jamais exécuté.

• Variables globales– Elles ont une portée de fichier.– Il est préférable dans ce cas d'utiliser un espace de

nom anonyme.• Membres de données (attributs)

– Il existe une unique instance d'un membre de données statiques partagée par toutes les instances de cette classe.

– Les membres de données static sont initialisés avant même l'appel de la fonction main

Page 188: Introduction à C++

Introduction à la programmation objet et générique avec C++ 188

Généralités sur le C++ (85) : un « meilleur C »Généralités sur le C++ (85) : un « meilleur C »•Classe de stockage : static (suite)

– La classe de stockage static a pour signification dans les cas suivants

• Fonctions indépendantes de toute classe– Elles ont une portée de fichier.– Il est préférable dans ce cas d'utiliser un espace de

noms anonyme.• Fonctions membres (méthodes)

– Elles peuvent être appelées sans passer par une instance de leur classe mais elles ne peuvent accéder qu'aux membres (données ou fonctions) également statiques de cette classe.

Page 189: Introduction à C++

Introduction à la programmation objet et générique avec C++ 189

Généralités sur le C++ (86) : un « meilleur C »Généralités sur le C++ (86) : un « meilleur C »•Classe de stockage : extern

– La classe de stockage extern signifie pour une variable globale ou pour une fonction indépendante de toute classe que sa définition a lieu dans un autre fichier source

– C'est la classe de stockage par défaut pour les fonctions indépendantes de toutes classe.

✔ Classe de stockage : mutable– Cette classe de stockage ne concerne que les membres de

données des classes.– Elle indique que la valeur de ce membre peut être modifiée

même si l'instance de classe comportant ce membre a été déclarée avec le mot-clé const.

✔ Classe de stockage : auto– La classe de stockage auto indique au compilateur d'allouer

automatiquement un espace de stockage à la variable correspondante à chaque fois que le bloc d'instructions est appelé.

– C'est la classe de stockage par défaut des variables locales– Le mot-clé auto est rarement utilisé explicitement.

Page 190: Introduction à C++

Introduction à la programmation objet et générique avec C++ 190

Généralités sur le C++ (87) : un « meilleur C »Généralités sur le C++ (87) : un « meilleur C »•Classe de stockage : register

– La classe de stockage register signifie qu'il est demandé à ce que l'adresse de la variable correspondante soit stockée dans un registre système pour de meilleures performances.

– L'opérateur d'adresse (« & ») ne peut donc être utilisé pour de telle variable.

– C'est le compilateur qui décide d'utiliser ou non un registre système.

Page 191: Introduction à C++

Introduction à la programmation objet et générique avec C++ 191

Généralités sur le C++ (88) : un « meilleur C »Généralités sur le C++ (88) : un « meilleur C »•Qualificatifs

– Il y a 2 qualificatifs en C++• const • volatile

– Ils peuvent être utilisés ensemble dans certains cas.

Page 192: Introduction à C++

Introduction à la programmation objet et générique avec C++ 192

Généralités sur le C++ (89) : un « meilleur C »Généralités sur le C++ (89) : un « meilleur C »•Qualificatifs : const

– Le qualificatif const empêche l'entité correspondante d'être modifiée

• Une exception : une instance de classe dont les membres de données sont déclarés mutable

– Utilisation de const• Variables locales

– Elles ne peuvent pas être modifiées après leur initialisation qui est obligatoire.

• Variables globales– Elles ne peuvent pas être modifiées après leur

initialisation qui est obligatoire.• Membres de données (attributs)

– Ils ne peuvent pas être modifiés après leur initialisation qui est obligatoire au moment de la construction de l'objet.

Page 193: Introduction à C++

Introduction à la programmation objet et générique avec C++ 193

Généralités sur le C++ (90) : un « meilleur C »Généralités sur le C++ (90) : un « meilleur C »•Qualificatifs : const (suite)

– Utilisation de const• Fonctions membres non statiques avec le mot-clé const

en fin de signature– Elles ne peuvent pas modifier des membres de

données non statiques de leur classe qui n'ont pas été déclarés comme mutable.

– Ces fonctions doivent être invoqués sur des instances déclarés également const.

• Paramètres de fonction– Leur valeur ne peut être modifiée au sein de la

fonction• Valeur de retour d'une fonction

– La valeur de retour ne peut être utilisée que là où une valeur const est autorisée.

Page 194: Introduction à C++

Introduction à la programmation objet et générique avec C++ 194

Généralités sur le C++ (91) : un « meilleur C »Généralités sur le C++ (91) : un « meilleur C »•Qualificatifs : const (fin)

– Utilisation de const avec des pointeurs• La déclaration de pointeurs const se fait différemment

selon ce qui doit être protéger : le pointeur ou le pointé. – Pour protéger ce qui est pointé (cas le plus courant),

on déclare const avant le type de pointeurint i = 100, j=200;const int *p = &i;*p = j ; //impossible : erreurp = &j; //autorisé

– Pour protéger le pointeur, le mot-clé const apparaît après l'astérisque (« * »).int i = 100, j=200;int *const p = &i;*p = j ; //autorisép = &j; //impossible : erreur

– Pour protéger les 2, on combine les 2 formes précédentes.

Page 195: Introduction à C++

Introduction à la programmation objet et générique avec C++ 195

Généralités sur le C++ (92) : un « meilleur C »Généralités sur le C++ (92) : un « meilleur C »•Qualificatifs : volatile

– Le qualificatif volatile indique au compilateur qu'une variable, un membre de donnée ou un paramètre de fonction peut être modifié inopinément

• Cette modification inopinée peut être due à un autre processus, à la configuration matérielle, etc.

– Cela permet au compilateur de supprimer les optimisations qui pourraient être incompatibles avec des modifications asynchrone de l'entité.

– Lorsqu'une instance de classe a été créée avec ce qualificatif, seules les fonctions membres également volatiles peuvent lui être appliquées.

• Ce qualificatif ne doit donc être appliqué à des fonctions membres que si l'on souhaite créer des objets volatiles et invoquer ces fonctions membres sur ces objets.

Page 196: Introduction à C++

Introduction à la programmation objet et générique avec C++ 196

Programmation orientée objet en C++

Page 197: Introduction à C++

Introduction à la programmation objet et générique avec C++ 197

Plan général du coursPlan général du cours✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques

• Livre• Web

– Les outils utilisés dans ce cours✔ Introduction aux concepts de la programmation orientée

objet– Conception et « Orienté Objet »– Les cartes CRC

✔ Introduction au C++– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 198: Introduction à C++

Introduction à la programmation objet et générique avec C++ 198

Introduction au C++ (2/4) : sommaireIntroduction au C++ (2/4) : sommaire✔ Introduction au C++

– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 199: Introduction à C++

Introduction à la programmation objet et générique avec C++ 199

Les Classes en C++ (1)Les Classes en C++ (1)✔ POO et classes en C++

– La POO en C++ repose sur le concept de classe• La classe est une généralisation du concept de type défini

par l'utilisateur (on parle parfois de type abstrait de données).

• Dans une classe se trouvent associées à la fois les données (on parle « d'attributs » ou de « membres données ») et des fonctions (on parle de « méthodes » ou de « fonctions membres »)

– Notion d'encapsulation• Dans la plupart des langages purement objet les données

sont encapsulées– On ne peut y accéder que via des méthodes.– par défaut les données sont « privées » aux objets, on

ne peut y accéder directement.– Visibilité

• En C++ comme en Java, on peut rendre choisir de rendre public ou privé tel attribut ou telle méthode.

Page 200: Introduction à C++

Introduction à la programmation objet et générique avec C++ 200

Les Classes en C++ (2)Les Classes en C++ (2)✔ Déclaration d'une classe

– Le mot clé pour déclarer une classe est le mot-clé class– La déclaration d'une classe précise quels sont les membres

(données ou fonctions) publics et quels sont les membres privés

• Membres publics : membres accessibles à l'utilisateur de cette classe. Utilisation du mot-clé public

• Membres privés : membres accessibles uniquement par les méthodes définies dans la classe. Utilisation du mot-clé private

– Ces membres sont inaccessibles à tout utilisateur de la classe.

Page 201: Introduction à C++

Introduction à la programmation objet et générique avec C++ 201

Les Classes en C++ (3)Les Classes en C++ (3)✔ Déclaration d'une classe (suite)

– En pratique, la déclaration de la classe se fera dans un fichier en-tête séparée, un peu comme on pouvait le faire en C pour les déclarations des fonctions.

• L'utilisateur d'une classe (on parle en général de « client ») inclura se fichier en-tête dans tout programme faisant appel à cette classe.

– Remarque : les déclarations « public » et « private » peuvent apparaître à plusieurs rerpises dans la déclaration d'une même classe.

– Par défaut, les membres d'une classe sont privés

Page 202: Introduction à C++

Introduction à la programmation objet et générique avec C++ 202

Les Classes en C++ (4)Les Classes en C++ (4)✔ Déclaration d'une classe : exemple

class Point{ /* déclaration des membres privés */ private : int x; int y; /* déclaration des membres publics */ public : void initialize(int abscissa, int ordinate); int getX(); int getY(); void setX(int abscissa); void setY(int ordinate); void display(); };

Page 203: Introduction à C++

Introduction à la programmation objet et générique avec C++ 203

Les Classes en C++ (5)Les Classes en C++ (5)✔ Définition d'une classe

– La définition d'une classe consiste à fournir les définitions des fonctions membres

• Pour se faire, on indique le nom de la classe correspondante, à l'aide de l'opérateur de résolution de portée (« :: »).

• Au sein de la définition même, les membres, qu'ils soient privées ou publics, attributs ou méthodes, sont directement accessibles sans qu'il soit nécessaire de préciser le nom de la classe.

– En pratique, on définira les fonctions membres dans un fichier séparés, associés au fichier en-tête dans laquelle se situe la déclaration de la classe. On parlera en général de fichier source de la classe.

Page 204: Introduction à C++

Introduction à la programmation objet et générique avec C++ 204

Les Classes en C++ (6)Les Classes en C++ (6)✔ Définition d'une classe : exemple

#include "Point.h"void Point::initialize(int abscissa, int ordinate){ x = abscissa; y = ordinate; }int Point::getX(){ return x; } int Point::getY(){ return y; }// ... etc.

Page 205: Introduction à C++

Introduction à la programmation objet et générique avec C++ 205

Les Classes en C++ (7)Les Classes en C++ (7)✔ Utilisation d'une classe

– Les classes définies par l'utilisateurs constituent des nouveaux types de données

– Pour déclarer un objet du type d'une classe, on procédera de la même manière que pour définir une variable d'un des types fondamentaux

• <type de la variable> <nom de la variable>;– On peut accéder à n'importe quel membre public d'une classe,

que cela soit un attribut ou une méthode, en utilisant l'opérateur « . »

• Similaire à ce que l'on utilisait pour accéder au champ membre d'une « struct »

• En C++ les « struct » et les « union » sont en fait des classes particulières.

Page 206: Introduction à C++

Introduction à la programmation objet et générique avec C++ 206

Les Classes en C++ (8)Les Classes en C++ (8)✔ Utilisation d'une classe : exemple

#include <iostream>#include <cstdlib>#include "Point.h"using namespace std;int main(int argc, char *argv[]){ Point p;//déclaration d'un objet point nommé p p.initialize(1,5);//j'appelle sur p la méthode initialize p.display();//j'appelle sur p la fonction membre display system("PAUSE"); return EXIT_SUCCESS;}

Page 207: Introduction à C++

Introduction à la programmation objet et générique avec C++ 207

Les Classes en C++ (9)Les Classes en C++ (9)✔ Exercice

– Déclarer et définir une classe Vecteur3D représentant un vecteur à 3 composantes réelles (on utilisera des doubles).

• On partira sur le modèle de la classe Point;• Les 3 composantes du vecteur seront nommées x, y et z

dans la classe• On souhaite

– définir des fonctions membres permettant d'accéder à la valeur des 3 composantes.

– définir une fonction membre réalisant l'initialisation d'un objet vecteur.

– Tester votre classe

Page 208: Introduction à C++

Introduction à la programmation objet et générique avec C++ 208

Les Classes en C++ (10)Les Classes en C++ (10)✔ Affectation d'objet

– C++ autorise l'affectation d'un objet d'un type donné à un autre objet de même type.

• Il y a alors recopie des valeurs des champs de données (qu'ils soient publics ou privés)

• Cependant, si parmi ces champs, il y a des pointeurs, les emplacements pointés ne seront pas soumis à la recopie

– L'adresse est bien recopiée, mais pas ce qui est pointée par cette adresse.

– Si on souhaite qu'il y ait une recopie complète (c'est-a-dire que même les emplacements pointés soient recopiées), il faudra surcharger l'opérateur d'affectation pour la classe concernée.

Page 209: Introduction à C++

Introduction à la programmation objet et générique avec C++ 209

Les Classes en C++ (11)Les Classes en C++ (11)✔ Constructeur

– Les constructeurs sont des fonctions membres particulières, utilisées pour initialiser les instances d'une classe.

• Elles permettent d'effectuer des actions d'initialisation après la création de l'objet mais avant son utilisation.

– Par exemple l'allocation de mémoire dynamique pour des attributs, l'ouverture de fichier, etc.

– Les constructeurs sont appelés à chaque fois qu'un espace mémoire est alloué pour un objet

• Que cela soit « automatiquement » par le compilateur (classe de stockage auto) comme dans l'exemple d'utilisation d'une classe précédent ou lorsque l'on utilise new ou new[] pour créer un pointeur sur un objet.

– Les constructeurs ont des particularités par rapport aux autres méthodes

• Ils ont toujours le même nom que leur classe• Ils n'ont pas de valeur de retour :

– il ne renvoie rien, même pas void

Page 210: Introduction à C++

Introduction à la programmation objet et générique avec C++ 210

Les Classes en C++ (12)Les Classes en C++ (12)✔ Constructeur : constructeur par défaut

– Les constructeurs par défaut sont des constructeurs qui ne prennent pas de paramètres ou dont les paramètres ont une valeur par défaut

– Si aucun constructeur n'est défini pour une classe donnée, le compilateur crée un un constructeur par défaut implicite.

• Il faut noter que lors de l'utilisation de new[] pour allouer un tableau d'objets, un constructeur par défaut doit être disponible

– Une fois qu'au moins un constructeur en plus du constructeur par défaut a été défini, il n'est plus possible de déclarer un objet du type correspondant sans fournir les arguments requis par ce constructeur.

Page 211: Introduction à C++

Introduction à la programmation objet et générique avec C++ 211

Les Classes en C++ (13)Les Classes en C++ (13)✔ Surcharge du constructeur

– Pour une même classe, on peut avoir plusieurs constructeurs différents

• On parle de surcharge ou de surdéfinition du constructeur.• Il faut que ces constructeurs soient différents par le type

de leurs paramètres.

Page 212: Introduction à C++

Introduction à la programmation objet et générique avec C++ 212

Les Classes en C++ (14)Les Classes en C++ (14)✔ Constructeur : exemple (1/3)

class Point{ /* déclaration des membres privés */ private : int x; int y; /* déclaration des membres publics */ public : Point(); //constructeur par défaut Point(int abscissa, int ordinate); //2ème constructeur int getX(); int getY(); void setX(int abscissa); void setY(int ordinate); void display(); };

Page 213: Introduction à C++

Introduction à la programmation objet et générique avec C++ 213

Les Classes en C++ (15)Les Classes en C++ (15)✔ Constructeur : exemple (2/3)

#include "Point.h"#include <iostream>using namespace std;Point::Point(){ x = 0; y = 0; }Point::Point(int abscissa, int ordinate){ x = abscissa; y = ordinate; }// ... etc.

Page 214: Introduction à C++

Introduction à la programmation objet et générique avec C++ 214

Les Classes en C++ (16)Les Classes en C++ (16)✔ Constructeur : exemple (3/3)

#include <iostream>#include <cstdlib>#include "Point.h"using namespace std;int main(int argc, char *argv[]){ Point p1; //déclaration et création d'un objet point p1 Point p2(1,5); //déclaration et création d'un objet point p2 p1.display();//j'appelle sur p1 la fonction membre display p2.display();//j'appelle sur p2 la fonction membre display system("PAUSE"); return EXIT_SUCCESS;}

Page 215: Introduction à C++

Introduction à la programmation objet et générique avec C++ 215

Les Classes en C++ (17)Les Classes en C++ (17)✔ Exercice

– Reprenez la classe Vecteur3D que vous avez précédemment défini

• Supprimer la fonction membre d'initialisation • Définir des constructeurs pour la classe Vecteur3D

– Tester votre classe

Page 216: Introduction à C++

Introduction à la programmation objet et générique avec C++ 216

Les Classes en C++ (18)Les Classes en C++ (18)✔ Destructeur

– Les destructeurs sont des fonctions membres spéciales appelées automatiquement lorsqu'une instance de classe est détruite.

• Ils permettent d'effectuer certaines actions de nettoyage– Par exemple, récupération de mémoire dynamique,

fermeture de fichiers, etc.• Les destructeurs sont appelés

– juste avant qu'un objet ne soit plus accessible dans la portée en cours

– lorsque la destruction explicite des objets est demandée par un appel à delete ou delete[] sur des pointeurs vers ces objets.

• Les destructeurs sont des méthodes particulières– Ils ont pour nom, le nom de la classe précédé du

symbole tilde (« ~ »).– Ils ne prennent aucun paramètre et non pas de valeur

de retour.

Page 217: Introduction à C++

Introduction à la programmation objet et générique avec C++ 217

Les Classes en C++ (19)Les Classes en C++ (19)✔ Pointeurs sur des objets

– Pour déclarer et allouer un pointeur sur une instance de classe, on procéde de la même manière que pour déclarer et allouer un pointeur sur n'importe quel type de données

• <nom_type> * <nom_variable>;• <nom_variable> = new <nom-type>;

– Dans le cas d'une classe, on pourra passer à la suite du new, les paramètres correspondant au constructeur que l'on souhaite utiliser.

– Pour accéder à un membre d'un objet à travers un pointeur sur cet objet, on utilise l'opérateur flèche vers la droite (« -> »), comme avec les pointeurs sur structure en C.

Page 218: Introduction à C++

Introduction à la programmation objet et générique avec C++ 218

Les Classes en C++ (20)Les Classes en C++ (20)✔ Exemple

#include <iostream>#include <cstdlib>#include "Point.h"using namespace std;int main(int argc, char *argv[]){ Point *p1 = new Point; //déclaration et création d'un pointeur sur point Point *p2 = new Point(1,5); //déclaration et création d'un pointeur sur point p1->display();//j'appelle sur p1 la fonction membre display p2->display();//j'appelle sur p2 la fonction membre display delete p1; delete p2; system("PAUSE"); return EXIT_SUCCESS;}

Page 219: Introduction à C++

Introduction à la programmation objet et générique avec C++ 219

Les Classes en C++ (21)Les Classes en C++ (21)✔ Exercice

– Modifier votre programme de test de la classe Vecteur3D pour manipuler des pointeurs sur des vecteurs, sur le modèle de l'exemple précédent.

Page 220: Introduction à C++

Introduction à la programmation objet et générique avec C++ 220

Les Classes en C++ (22)Les Classes en C++ (22)✔ Compléments sur la déclaration des membres de données

– La déclaration de membres de données non statiques constitue également leur définition.

– Il n'est pas possible d'initialiser un membre de données non statique lors de sa définition

• Les membres statiques quant à eux sont définis en dehors de la classe.

– Les seules classes de stockages autorisées pour un attribut sont static et mutable

– Chaque instance de classe créée possède sa propre copie des attributs, à l'exception de ceux déclarés avec le mot-clé static

• ils sont dans ce dernier cas partagés par toutes les instances

Page 221: Introduction à C++

Introduction à la programmation objet et générique avec C++ 221

Les Classes en C++ (23)Les Classes en C++ (23)✔ Les membres de données constants

– Les membres de données constants ne peuvent pas être modifiés.

– Ils sont déclarés avec le mot-clé const devant le type.– Ces membres de données doivent être initialisés par le

constructeur, sauf dans le cas des données membres statiques.

• Pour les membres de données constants et statiques, l'initialisation se fait comme pour un membre statique non-constant.

– Il est intéressant de déclarer un membre de données constant comme statique lorsque sa valeur doit être la même pour toutes les instances de la classe.

Page 222: Introduction à C++

Introduction à la programmation objet et générique avec C++ 222

Les Classes en C++ (24)Les Classes en C++ (24)✔ Initialisation des membres de données (1/4)

– L'initialisation des membres de données peut-être effectuée avant même l'exécution du constructeur.

• Elle peut se faire au niveau de la définition du constructeur en plaçant la liste d'éléments à initialiser entre la signature du constructeur et son corps.

– Cette liste commence par le symbole « : » et ses éléments sont séparés par des virgules.

– Les membres de données non statiques déclarés comme constants ou comme référence doivent obligatoirement être initialisés ainsi.

– Pour initialiser des membres de données qui sont eux-mêmes des objets, il suffit de donner une liste de paramètres à l'élément d'initialisation correspondant à la signature d'un constructeur de cet objet.

Page 223: Introduction à C++

Introduction à la programmation objet et générique avec C++ 223

Les Classes en C++ (25)Les Classes en C++ (25)✔ Initialisation des membres de données (2/4)

– L'ordre d'initialisation des membres de données est celui dans lequel ils sont déclarés à l'intérieur de la classe et non celui dans lequel ils apparaissent dans la liste d'initialisation.

– Les membres de données statiques ne peuvent pas être initialisés ainsi.

• Ils doivent être initialisés lors de leur définition en dehors de la classe.

Page 224: Introduction à C++

Introduction à la programmation objet et générique avec C++ 224

Les Classes en C++ (26)Les Classes en C++ (26)✔ Initialisation des membres de données (3/4)

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant); void retirer(double montant); double donnerSolde() const; int getNombreConsultations() const; };

Page 225: Introduction à C++

Introduction à la programmation objet et générique avec C++ 225

Les Classes en C++ (27)Les Classes en C++ (27)✔ Initialisation des membres de données (4/4)

#include "CompteBancaire.h"using namespace std//initialisation de l'attribut statiqueint CompteBancaire::nombre_comptes = 0;CompteBancaire::CompteBancaire() : SOLDE_MINIMUM(0.0),solde(0.0){ nombreConsultations = 0; CompteBancaire::nombre_comptes ++; }CompteBancaire::CompteBancaire(double s) : SOLDE_MINIMUM(0.0),solde(s){ nombreConsultations = 0; CompteBancaire::nombre_comptes ++; }

Page 226: Introduction à C++

Introduction à la programmation objet et générique avec C++ 226

Les Classes en C++ (28)Les Classes en C++ (28)✔ Les membres de données statiques

– Les membres de données statiques sont partagés par toutes les instances de la classe

– Ils sont déclarés avec le mot-clé static.– Contrairement à la déclaration d'un membre non-statique, la

déclaration d'un membre de données statique, ne joue pas un rôle de définition.

• Le membre de donnée statique doit obligatoirement être défini en dehors de la classe, ce qui est généralement accompagné d'une initialisation de sa valeur.

• Pour accéder à un membre de données statique à l'extérieur de sa classe, il faut utiliser le nom de la classe avec l'opérateur de portée (« :: »).

– Il est possible d'accéder à un membre statique même sans qu'il y ait eu création d'instances pour cette classe.

Page 227: Introduction à C++

Introduction à la programmation objet et générique avec C++ 227

Les Classes en C++ (29)Les Classes en C++ (29)✔ Les membres de données statiques (suite)

– Le spécificateur d'accès (private ou public par exemple) indiqué pour un membre de données statique n'est pas pris en compte lors de la définition de ce membre.

• Pour pouvoir y accéder pour le définir même quand il est private.

– La définition de membres de données statiques se fait dans le fichier source de la classe et non dans le fichier en-tête

• En effet, si on la place dans le fichier en-tête, les attributs statiques seraient définis à chaque inclusion du fichier en-tête.

Page 228: Introduction à C++

Introduction à la programmation objet et générique avec C++ 228

Les Classes en C++ (30)Les Classes en C++ (30)✔ Les membres de données statiques (fin)

– Il est intéressant de déclarer un attribut constant comme statique lorsque sa valeur doit être la même pour toutes les instances de la classe.

• Cela préserve en effet de la mémoire puisque toutes les instances de la classe partagent alors le même membre.

– Pour les membres de données statique et constant, on procéde à l'initialisation comme pour un membre de donnée uniquement statique

• l'initialisation se fait à l'extérieur de la classe et non via le constructeur.

• On utilise le nom de la classe et l'opérateur de portée.

Page 229: Introduction à C++

Introduction à la programmation objet et générique avec C++ 229

Les Classes en C++ (31)Les Classes en C++ (31)✔ Les membres de données mutable

– Les membres de données mutable peuvent être modifiés même si l'objet qui les référence a été déclaré comme étant constant

• Mot-clé mutable• Le mot-clé mutable est placé avant le type dans la

déclaration de l'attribut.

Page 230: Introduction à C++

Introduction à la programmation objet et générique avec C++ 230

Les Classes en C++ (32)Les Classes en C++ (32)✔ Les membres de données mutable : exemple (1/3)

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant); void retirer(double montant); double donnerSolde() const; int getNombreConsultations() const; };

Page 231: Introduction à C++

Introduction à la programmation objet et générique avec C++ 231

Les Classes en C++ (33)Les Classes en C++ (33)✔ Les membres de données mutable : exemple (2/3)

#include "CompteBancaire.h"using namespace std;//... double CompteBancaire::donnerSolde() const{ nombreConsultations ++; return solde; }int CompteBancaire::getNombreConsultations() const{ return nombreConsultations;}

Page 232: Introduction à C++

Introduction à la programmation objet et générique avec C++ 232

Les Classes en C++ (34)Les Classes en C++ (34)✔ Les membres de données mutable : exemple (3/3)

#include <cstdlib>#include <iostream>#include "CompteBancaire.h"using namespace std;int main(int argc, char *argv[]){ const CompteBancaire c_b_1(100.0); //on ne peut modifier un objet "const" c_b_1.retirer(50.0);//erreur //sauf ces champs mutables, avec des méthodes « constantes » int nbconsult = c_b_1.getNombreConsultations(); cout << "Le nombre de consultation : " << nbconsult << endl; cout << "Le solde : " << c_b_1.donnerSolde() << endl; nbconsult = c_b_1.getNombreConsultations(); cout << "Le nombre de consultation : " << nbconsult << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 233: Introduction à C++

Introduction à la programmation objet et générique avec C++ 233

Les Classes en C++ (35)Les Classes en C++ (35)✔ Les fonctions membres : complément (1/5)

– Les règles de déclaration et de définition de fonctions membres sont semblables à celles des fonctions indépendantes de toutes classes, avec les exception suivantes

• Pour les fonctions membres on peut utiliser le mot-clé virtual pour utiliser le polymorphisme

• La seule classe de stockage autorisée pour une fonction membre est static

• Une fonction membre non-statique ne peut être invoquée que sur un objet de la classe dans laquelle elle est définie.

Page 234: Introduction à C++

Introduction à la programmation objet et générique avec C++ 234

Les Classes en C++ (36)Les Classes en C++ (36)✔ Les fonctions membres : complément (2/5)

– Lors de la déclaration d'une fonction membre, il est possible de donner ou non sa définition

• Si on donne sa définition, il faut simplement faire suivre la signature du corps de la fonction.

• Les fonctions membres ainsi définies dans la définition de leur classe sont considérées comme des fonctions inline, sauf si elles sont également déclarées virtual.

• Quand on définit une fonction membre en dehors de la définition de sa classe, il faut utiliser le nom de la classe est l'opérateur de portée « :: »

– Dans ce cas, pour que la fonction membre soit manipulée comme une fonction en ligne, il faut explicitement précéder sa définition du mot-clé inline.

Page 235: Introduction à C++

Introduction à la programmation objet et générique avec C++ 235

Les Classes en C++ (37)Les Classes en C++ (37)✔ Les fonctions membres : complément (3/5)

– La définition des fonctions membres en dehors de leur classe doit se faire dans le fichier source de la classe et non dans son fichier en-tête

• Sinon la fonction membre serait définie plus d'une fois, si le fichier en-tête est importé plus d'une fois

• Exception – Les fonctions inline– Les fonctions membres de classes patron

• Elles doivent être définies dans les fichiers en-têtes de leur classe

Page 236: Introduction à C++

Introduction à la programmation objet et générique avec C++ 236

Les Classes en C++ (38)Les Classes en C++ (38)✔ Les fonctions membres : complément – exemple (4/5)

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant) { solde = solde + montant; } void retirer(double montant) { solde = solde - montant; } double donnerSolde(); int getNombreConsultations() const; };

Page 237: Introduction à C++

Introduction à la programmation objet et générique avec C++ 237

Les Classes en C++ (39)Les Classes en C++ (39)✔ Les fonctions membres : complément – exemple (5/5)

#include <cstdlib>#include <iostream>#include "CompteBancaire.h"using namespace std;int main(int argc, char *argv[]){ CompteBancaire c_b_1(100.0); c_b_1.retirer(50.0); cout << "Le solde : " << c_b_1.donnerSolde() << endl; c_b_1.deposer(75.0); cout << "Le solde : " << c_b_1.donnerSolde() << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 238: Introduction à C++

Introduction à la programmation objet et générique avec C++ 238

Les Classes en C++ (40)Les Classes en C++ (40)✔ Les fonctions membres constantes (1/4)

– Les fonctions membres constantes sont les seules fonctions membres non-statiques qu'il soit possible d'appeler sur des objets déclarés avec le mot-clé const

• Pour déclarer une telle propriété il suffit d'ajouter le mot-clé const en fin de siganture

– Une fonction membre constante ne peut modifier des membres de données non statiques qui n'ont pas été déclarés avec le mot-clé mutable ou appeler d'autres fonctions membres qui ne sont pas elles aussi constantes

• En dehors de l'utilisation avec des champs mutable, il est recommandé pour cette raison d'utiliser des fonctions constantes pour implémenter des fonctions d'accès aux champs de l'objet.

Page 239: Introduction à C++

Introduction à la programmation objet et générique avec C++ 239

Les Classes en C++ (41)Les Classes en C++ (41)✔ Les fonctions membres constantes – exemple (2/4)

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant); void retirer(double montant); double donnerSolde() const; int getNombreConsultations() const; };

Page 240: Introduction à C++

Introduction à la programmation objet et générique avec C++ 240

Les Classes en C++ (42)Les Classes en C++ (42)✔ Les fonctions membres constantes – exemple (3/4)

#include "CompteBancaire.h"using namespace std;//... double CompteBancaire::donnerSolde() const{ nombreConsultations ++; return solde; }int CompteBancaire::getNombreConsultations() const{ return nombreConsultations;}

Page 241: Introduction à C++

Introduction à la programmation objet et générique avec C++ 241

Les Classes en C++ (43)Les Classes en C++ (43)✔ Les fonctions membres constantes – exemple (4/4)

#include <cstdlib>#include <iostream>#include "CompteBancaire.h"using namespace std;int main(int argc, char *argv[]){ const CompteBancaire c_b_1(100.0); //on ne peut modifier un objet "const" c_b_1.retirer(50.0);//erreur //sauf ces champs mutables, avec des méthodes « constantes » int nbconsult = c_b_1.getNombreConsultations(); cout << "Le nombre de consultation : " << nbconsult << endl; cout << "Le solde : " << c_b_1.donnerSolde() << endl; nbconsult = c_b_1.getNombreConsultations(); cout << "Le nombre de consultation : " << nbconsult << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 242: Introduction à C++

Introduction à la programmation objet et générique avec C++ 242

Les Classes en C++ (44)Les Classes en C++ (44)✔ Les fonctions membres statiques (1/4)

– Les fonctions membres statiques peuvent être invoquées sur une instance de classe ou non.

• Pour déclarer une telle fonction, il suffit d'utiliser le mot-clé static

• Pour appeler une fonction membre statique sans passer par une instance de cette classe, il faut utiliser le nom de la classe et l'opérateur de résolution de portée.

• Une fonction membre statique ne peut accéder directement aux membres de données et aux fonctions membres non-statiques.

Page 243: Introduction à C++

Introduction à la programmation objet et générique avec C++ 243

Les Classes en C++ (45)Les Classes en C++ (45)✔ Les fonctions membres statiques – exemple (2/4)

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant); void retirer(double montant); double donnerSolde() const; int getNombreConsultations() const; static int getNombreComptes(); };

Page 244: Introduction à C++

Introduction à la programmation objet et générique avec C++ 244

Les Classes en C++ (46)Les Classes en C++ (46)✔ Les fonctions membres statiques – exemple (3/4)

#include "CompteBancaire.h"using namespace std;//initialisation de l'attribut statiqueint CompteBancaire::nombre_comptes = 0;//...int CompteBancaire::getNombreComptes(){ return CompteBancaire::nombre_comptes;}

Page 245: Introduction à C++

Introduction à la programmation objet et générique avec C++ 245

Les Classes en C++ (47)Les Classes en C++ (47)✔ Les fonctions membres statiques – exemple (4/4)

#include <cstdlib>#include <iostream>#include "CompteBancaire.h"using namespace std;int main(int argc, char *argv[]){ CompteBancaire c_b_1(100.0); cout << "Le solde : " << c_b_1.donnerSolde() << endl; cout << "Nombre de compte : " << CompteBancaire::getNombreComptes() << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 246: Introduction à C++

Introduction à la programmation objet et générique avec C++ 246

Les Classes en C++ (48)Les Classes en C++ (48)✔ Le pointeur this (1/2)

– Toutes les fonctions membres non-statiques ont accès à un pointeur spécial qui référence l'objet sur lequel on a invoqué la fonction membre

• Le pointeur this– En fait l'accès à des membres de données depuis leur classe

passent par l'utilisation implicite du pointeur this• En général, on l'omet.

– Les fonctions déclarées static n'ont pas accès à ce pointeur this.

Page 247: Introduction à C++

Introduction à la programmation objet et générique avec C++ 247

Les Classes en C++ (49)Les Classes en C++ (49)✔ Le pointeur this – exemple (2/2)

#include "CompteBancaire.h"using namespace std//initialisation de l'attribut statiqueint CompteBancaire::nombre_comptes = 0;CompteBancaire::CompteBancaire() : SOLDE_MINIMUM(0.0){ this->solde = 0.0; this->nombreConsultations = 0; CompteBancaire::nombre_comptes ++; }// ...

Page 248: Introduction à C++

Introduction à la programmation objet et générique avec C++ 248

Les Classes en C++ (50)Les Classes en C++ (50)✔ Les constructeurs de copies (1/7)

– Les constructeurs de copie sont des constructeurs spéciaux qui prennent en paramètre une référence vers une instance de la même classe

• En général une référence constante vers une instance de la forme const Type& parameter

– L'intérêt d'un paramètre déclaré comme une référence constante est de passer l'adresse d'un objet (qui est potentiellement une grosse structure en mémoire) tout en interdisant son accès en écriture au sein de la fonction.

– Il n'y a pas que les constructeurs de copie pour lesquelles on utilise des références constantes comme paramètre

• On peut avoir des paramètres déclarés comme référence ou référence constante pour les autres types de fonctions et de fonctions membres.

Page 249: Introduction à C++

Introduction à la programmation objet et générique avec C++ 249

Les Classes en C++ (51)Les Classes en C++ (51)✔ Les constructeurs de copies (2/7)

– Les constructeurs de copie font une copie de l'instance donnée en paramètre au sein de l'instance en cours de création.

• Ils peuvent éventuellement avoir des paramètres supplémentaires mais dans ce cas il faut qu'ils aient des valeurs par défaut.

Page 250: Introduction à C++

Introduction à la programmation objet et générique avec C++ 250

Les Classes en C++ (52)Les Classes en C++ (52)✔ Les constructeurs de copies (3/7)

– Les constructeurs de copie sont invoqués par le compilateur dans les cas suivants :

• Une instance de classe est passée par valeur à une fonction

– Un objet temporaire est créé dans la fonction, avec les valeurs du paramètre

• Une instance de classe est retournée par une fonction– On retourne une copie de l'objet qui a été créé dans la

fonction• Une instance de classe est initialisée avec une autre

instance• Une instance de classe est passée explicitement comme

seul paramètre du constructeur

Page 251: Introduction à C++

Introduction à la programmation objet et générique avec C++ 251

Les Classes en C++ (52)Les Classes en C++ (52)✔ Les constructeurs de copies (4/7)

– Si on ne fournit pas un constructeur de copie pour une classe, le compilateur en crée un implicitement.

– Si on fournit un constructeur de copie, il est courant de surcharger également l'opérateur d'affectation.

• Le constructeur de copie ou l'opérateur d'affectation par défaut effectue une copie membre à membre.

– Ainsi lors d'une initialisation faisant appel au constructeur de copie ou d'une affectation, la valeur des champs pointeurs de votre objet est recopiée, mais pas les éléments pointés, ce qui peut amener quelques petits problèmes si on n'y prend pas garde.

– Pour obtenir une copie en profondeur où tout est recopié, y compris les objets pointés, il faut définir un constructeur de copie et surcharger/surdéfinir l'opérateur d'affectation

• Le constructeur de copie pour les initialisation• L'opérateur d'affectation, pour les affectations

entre objets de cette classe.

Page 252: Introduction à C++

Introduction à la programmation objet et générique avec C++ 252

Les Classes en C++ (53)Les Classes en C++ (53)✔ Les constructeurs de copies – exemple (4/6)

class Point{ /* déclaration des membres privés */ private : int x; int y; /* déclaration des membres publics */ public : Point(); //constructeur par défaut Point(int abscissa, int ordinate); //2ème constructeur Point(const Point &pt); //constructeur de copie int getX(); int getY(); void setX(int abscissa); void setY(int ordinate); void display(); Point &operator=(const Point &pt) { this->x = pt.x; this->y = pt.y;

return *this; } };

Page 253: Introduction à C++

Introduction à la programmation objet et générique avec C++ 253

Les Classes en C++ (54)Les Classes en C++ (54)✔ Les constructeurs de copies – exemple (5/6)

#include "Point.h"#include <iostream>using namespace std;Point::Point(){ x = 0; y = 0; }// ...Point::Point(const Point &pt){ this->x=pt.x; this->y=pt.y; }// ...

Page 254: Introduction à C++

Introduction à la programmation objet et générique avec C++ 254

Les Classes en C++ (55)Les Classes en C++ (55)✔ Les constructeurs de copies – exemple (6/6)

#include <iostream>#include <cstdlib>#include "Point.h"using namespace std;int main(int argc, char *argv[]){ Point p1(1,5); Point p2 = p1; Point p3(4,6); p1.display(); p2.display(); p3.display(); p3 = p2; p3.display(); system("PAUSE"); return EXIT_SUCCESS;}

Page 255: Introduction à C++

Introduction à la programmation objet et générique avec C++ 255

Les Classes en C++ (56)Les Classes en C++ (56)✔ Déclaration par avance

– Il est possible de déclarer une classe sans la définir immédiatement.

• Pour cela, il faut utiliser une déclaration par avance, en ne déclarant que son nom

• Par exemple– class Point;

– Le compilateur s'attend donc à ce que la classe soit définie plus tard et il vous permet alors d'utiliser le nom de la classe tant que vous ne faites référence à aucun de ces membres.

– Les déclarations par avance sont utiles lorsque 2 classes se font mutuellement référence

Page 256: Introduction à C++

Introduction à la programmation objet et générique avec C++ 256

Les Classes en C++ (57)Les Classes en C++ (57)✔ Exercice de synthèse

– Reprenez votre classe Vecteur3D• Introduisez un constructeur de copie• Définissez les fonctions membres suivantes

– Une fonction d'affichage des 3 composantes du vecteur sous la forme

• <composante1, composante2, composante3>– Une fonction permettant d'obtenir la somme de 2

vecteurs– Une fonction calculant le produit scalaire de 2 vecteurs

Page 257: Introduction à C++

Introduction à la programmation objet et générique avec C++ 257

Les Classes en C++ (58)Les Classes en C++ (58)✔ Les structures en C++

– Les structures en C++ sont fonctionnellement identiques aux classes

• Pour définir une structure, il suffit d'utiliser le mot-clé struct là où vous auriez utilisé le mot-clé class

• Par rapport à une classe, une structure a comme spécificateur d'accès par défaut public et non privé

• L'intérêt des structures en C++ par rapport aux classes est quand même limité...

Page 258: Introduction à C++

Introduction à la programmation objet et générique avec C++ 258

Les Classes en C++ (59)Les Classes en C++ (59)✔ Les union en C++

– Les union en C++ sont semblables aux classes mais elles ne peuvent conserver de valeur que pour un seul membre de données à la fois.

• Mot-clé union• Une union ne prend donc pour place mémoire que

l'espace de stockage du membre de données le plus important.

– Les autres différences entre les unions et les classes• Le spécificateur d'accès par défaut est public et non privé• Les unions ne peuvent comporter de fonctions membres

déclarées avec le mot-clé virtual• Les unions ne peuvent hériter de rien et ne peuvent être

dérivées ;• Les membres des unions ne peuvent être des objets de

classes pourvues de constructeurs, de destructeurs ni de classes surchargeant l'opérateur d'affectation

• L'intérêt des union en C++ est limité ...

Page 259: Introduction à C++

Introduction à la programmation objet et générique avec C++ 259

Les fonctions et les classes amies (1)Les fonctions et les classes amies (1)✔ Rappels

– En C++, l'unité de protection est la classe et non l'objet• Ainsi, une fonction membre d'une classe peut accéder à

tous les membres privés de n'importe quel objet de sa classe.

– Par contre, le membre privé d'une classe est inacessible à toute fonction membre d'une autre classe ou à toute fonction indépendante.

✔ Notion « d'amies d'une classe » – La notion d'amie(s) d'une classe permet de déclarer dans

cette classe les fonctions ou les classes que l'on autorise à accèder à ses membres privés (données ou fonctions).

– Il est possible de déclarer comme amie des fonctions indépendantes de toute classe, des opérateurs surchargées, des fonctions membres d'une classe ou des classes complètes

Page 260: Introduction à C++

Introduction à la programmation objet et générique avec C++ 260

Les fonctions et les classes amies (2)Les fonctions et les classes amies (2)✔ Les amies d'une classe 

– La déclaration d'amies d'une classe peut se faire n'importe où dans la définition d'une classe mais se trouve habituellement au début de celle-ci ;

– Le spécificateur d'accès correspondant à la déclaration des amies n'a pas d'importance ;

– Le caractère ami n'est pas hérité.– Mot-clé : friend

✔ fonction amie d'une classe– Pour déclarer une fonction amie d'une classe, dans la

déclaration de cette classe je vais déclarer le prototype de la fonction précédé du mot-clé friend.

Page 261: Introduction à C++

Introduction à la programmation objet et générique avec C++ 261

Les fonctions et les classes amies (3)Les fonctions et les classes amies (3)✔ fonction amie d'une classe – exemple (1/2)

class Point{ friend void display(const Point& p); /* déclaration des membres privés */ private : int x; int y; /* déclaration des membres publics */ public : Point(); //constructeur par défaut Point(int abscissa, int ordinate); //2ème constructeur Point(const Point &pt); //constructeur de copie int getX(); int getY(); int setX(int abscissa); int setY(int ordinate); Point &operator=(const Point &pt); };

Page 262: Introduction à C++

Introduction à la programmation objet et générique avec C++ 262

Les fonctions et les classes amies (4)Les fonctions et les classes amies (4)✔ fonction amie d'une classe – exemple (2/2)

#include <iostream>#include <cstdlib>#include "Point.h"using namespace std;int main(int argc, char *argv[]){ Point p1(1,5); display(p1); system("PAUSE"); return EXIT_SUCCESS;}void display(const Point& p){ cout << "(" << p.x << "," << p.y << ")" <<endl; }

Page 263: Introduction à C++

Introduction à la programmation objet et générique avec C++ 263

Les fonctions et les classes amies (5)Les fonctions et les classes amies (5)✔ Une fonction membre amie d'une classe 

– La fonction membre <type_retour> methode(<liste_param>), membre de la classe B, est autorisée à accéder aux membres privés de la classe A

– Pour que la compilation puisse se faire, il faut qu'au moment de cette déclaration d'amitié, le compilateur connaisse la déclaration de B.

• Réciproquement si la fonction membre méthode retourne un objet de la classe B (ce qui peut justifier la déclaration d'amitié), pour que cela passe à la compilation pour la déclaration, il faudra peut-être faire une déclaration par avance la classe A (class A;) si elle n'est pas connue à ce niveau.

class A{ //... friend <type_retour> B::methode(<liste_param>); //...}

Page 264: Introduction à C++

Introduction à la programmation objet et générique avec C++ 264

Les fonctions et les classes amies (6)Les fonctions et les classes amies (6)✔ Une classe amie d'une autre classe 

– Si on souhaite que toutes les fonctions membres d'une classe B soient « amies » d'une autre classe A, dans ce cas on déclare directement que B est l'amie de A.

class A{ //... friend class B; //...}

Remarque : ne pas abuser de « l'amitié ». La plupart du temps on peut faire sans utiliser des déclarations d'amitié entre une classe et des fonctions ou d'autres classes. La notion de fonction amie sert principalement pour surdéfinir les opérateurs pour les types de données utilisateurs.

Page 265: Introduction à C++

Introduction à la programmation objet et générique avec C++ 265

Surdéfinition des opérateurs (1)Surdéfinition des opérateurs (1)✔ Surdéfinition et opérateurs

– On parle de surcharge ou de surdéfinition d'opérateur.• Lorsque l'on surdéfinit un opérateur on lui donne une

nouvelle signification lorsqu'il porte sur des objets de type classe.

– En C++ les opérateurs ont un comportement définis avec certains types intrinsèques (les types fondamentaux et les classes de la bibliothèque standard).

• Ce comportement ne peut pas être modifié• Néanmoins, il est possible de définir un comportement

additionnel pour les types définis par l'utilisateur.– Il est par exemple courant de redéfinir l'opérateur

« << » pour qu'il puisse être utilisé avec cout pour afficher correctement les objets d'un type utilisateur ou l'opérateur « >> » avec cin.

Page 266: Introduction à C++

Introduction à la programmation objet et générique avec C++ 266

Surdéfinition des opérateurs (2)Surdéfinition des opérateurs (2)✔ Mécanisme de le surdéfinition des opérateurs

– Pour surdéfinir un opérateur op, on définit une fonction nommée operator op

• on peut placer 0, 1 ou plusieurs espaces entre le mot operator et l'opérateur op.

• Pour définir cette fonction soit– on la définit sous forme d'une fonction membre d'une

classe• Dans ce cas, l'objet sur lequel l'opérateur est

appelé est le premier opérande. – on la définit sous la forme d'une fonction indépendante

• Dans ce cas toutes les opérandes sont passés à la fonction

• Généralement dans ce cas, elle est déclarée « amie » des types de classes de ses paramètres, afin de pouvoir accéder aux membres non publics de ces classes.

Page 267: Introduction à C++

Introduction à la programmation objet et générique avec C++ 267

Surdéfinition des opérateurs (3)Surdéfinition des opérateurs (3)✔ Exemple de surdéfinition des opérateurs (1/3)

#include <iostream>using namespace std;class Point{ friend ostream& operator<<(ostream& os, const Point& p); friend istream& operator>>(istream& is, Point& p); /* déclaration des membres privés */ private : int x; int y; /* déclaration des membres publics */ public : Point(); //constructeur par défaut Point(int abscissa, int ordinate); //2ème constructeur Point(const Point &pt); //constructeur de copie int getX(); int getY(); int setX(int abscissa); int setY(int ordinate); Point& operator=(const Point &pt);};

Page 268: Introduction à C++

Introduction à la programmation objet et générique avec C++ 268

Surdéfinition des opérateurs (4)Surdéfinition des opérateurs (4)✔ Exemple de surdéfinition des opérateurs (2/3)

#include "Point.h"using namespace std;//...Point& Point::operator=(const Point &pt){ this->x = pt.x; this->y = pt.y; return *this; } ostream& operator<<(ostream& os, const Point& pt){ os << "(" << pt.x << "," << pt.y << ")"; return os; } istream& operator>>(istream& is, Point& pt){ is >> pt.x >> pt.y; return is;}

Page 269: Introduction à C++

Introduction à la programmation objet et générique avec C++ 269

Surdéfinition des opérateurs (5)Surdéfinition des opérateurs (5)✔ Exemple de surdéfinition des opérateurs (3/3)

#include "Point.h"#include <cstdlib>using namespace std;int main(int argc, char *argv[]){ Point p1; cout << "entrer les coordonnées du point" << endl; cin >> p1; cout << endl; cout << p1 <<endl; Point p2; p2 = p1; cout << endl; cout << p2 <<endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 270: Introduction à C++

Introduction à la programmation objet et générique avec C++ 270

Surdéfinition des opérateurs (7)Surdéfinition des opérateurs (7)✔ Quelques règles pour la surdéfinition des opérateurs (1/2)

– Les opérateurs suivants ne peuvent pas être surchargés• ::• .• *• ? :• sizeof • typeid • Les opérateurs de conversions du C++ (dynamic_cast, static_cast, const_cast, reinterpret_cast)

– L'associativité et la précédence d'un opérateur ne peuvent être changés par la surcharge

– Les classes dérivées héritent des fonctions surchargeant les opérateurs, à l'exception de celles surchargeant l'opérateur d'affectation

Page 271: Introduction à C++

Introduction à la programmation objet et générique avec C++ 271

Surdéfinition des opérateurs (8)Surdéfinition des opérateurs (8)✔ Quelques règles pour la surdéfinition des opérateurs (2/2)

– Les fonctions surchargeant des opérateurs ne peuvent pas avoir de paramètres par défaut.

• Exception : l'opérateur ()– Cet opérateur accepte les paramètres par défaut et

peut comporter n'importe quel nombre de paramètres.– Les objets des classes qui surchargent l'opérateur ()

sont appelés objets fonctions.– Il est possible d'appeler explicitement une fonction

surchargeant un opérateur• a.operator+(b)

– Les opérateurs =, [], (), ->, new et delete doivent obligatoirement être définis comme fonctions membres.

Page 272: Introduction à C++

Introduction à la programmation objet et générique avec C++ 272

Surdéfinition des opérateurs (9)Surdéfinition des opérateurs (9)✔ Surdéfinition de l'opérateur d'affectation

– Il est courant de surcharger l'opérateur d'affectation d'une classe lorsqu'un constructeur de copie est défini

– L'opérateur d'affectation ne peut être surchargé que par une fonction membre

– Si l'opérateur d'affectation n'est pas surchargé, par défaut une affectation membre à membre est réalisée.

– Une fonction surchargeant l'opérateur d'affectation d'une classe n'est pas héritée par les classes dérivées.

– Pour cet opérateur, on peut choisir de transmettre son unique argument par valeur ou par référence

• Si on effectue le passage par référence, il faut faire attention que le seul moyen d'autoriser l'affectation d'une expression consiste à déclarer cet argument constant.

– Il faut donc passer une référence constante dans ce cas.

Page 273: Introduction à C++

Introduction à la programmation objet et générique avec C++ 273

Surdéfinition des opérateurs (10)Surdéfinition des opérateurs (10)✔ Surdéfinition des opérateus new et delete

– La surdéfinition de new, pour une classe donnée se fait par une fonction prototype

• void * new(size_t)• Cette fonction reçoit un unique argument, la taille de l'objet

à allouer et doit fournir en retour l'adresse de l'objet alloué– La taille passé en paramètre est générée

automatiquement par le compilateur lors de l'appel de new

– La surdéfinition de delete, pour un type donné, se fait par une fonction prototype

• void delete (type *)• Cette fonction reçoit un uniquement argument, l'adresse

de l'objet à libérer.

Page 274: Introduction à C++

Introduction à la programmation objet et générique avec C++ 274

Surdéfinition des opérateurs (10)Surdéfinition des opérateurs (10)✔ Cas de l'opérateur <<

– L'opérateur << est surdéfini par la classe ostream.– On peut redéfinir cet opérateur, pour pouvoir l'utiliser avec cout pour les objets des classes utilisateurs que nous avons défini.

– On le surdéfinira sous la forme d'une fonction amie, en utilisant le canevas présenté ci-après.

• Il faut noter que l'objet de type type_classe passé en paramètre peut l'être par valeur ou par référence.

– Il faudra inclure le fichier en-tête <iostream> ou <ostream> pour la déclaration et pour la définition

ostream& operator<< (ostream& sortie, type_classe objet){ //Envoi sur le flot de sortie des données membres de objet //en utilisant les possibilités classiques de << pour les //types de base return sortie; //on renvoie une référence vers l'objet ostream pour //pouvoir enchainer les opérations de sorties}

Page 275: Introduction à C++

Introduction à la programmation objet et générique avec C++ 275

Surdéfinition des opérateurs (11)Surdéfinition des opérateurs (11)✔ Cas de l'opérateur << : exemple

ostream& operator<<(ostream& os, const Point& pt){ os << "(" << pt.x << "," << pt.y << ")"; return os; }

Page 276: Introduction à C++

Introduction à la programmation objet et générique avec C++ 276

Surdéfinition des opérateurs (12)Surdéfinition des opérateurs (12)✔ Cas de l'opérateur >>

– L'opérateur >> est surdéfini par la classe istream.– On peut redéfinir cet opérateur, pour pouvoir l'utiliser avec cin

pour les objets des classes utilisateurs que nous avons défini.– On le surdéfinira sous la forme d'une fonction amie, en

utilisant le canevas présenté ci-après.– Il faudra inclure le fichier en-tête <iostream> ou <istream>

pour la déclaration et pour la définition

istream& operator>> (istream& entree, type_classe& objet){ //Lecture des informations correspondant aux différents //membres de « objet » en utilisant les possibilités //classiques de >> pour les types de base return entree; //on renvoie une référence vers l'objet istream pour //pouvoir enchainer les opérations d'entrée}

Page 277: Introduction à C++

Introduction à la programmation objet et générique avec C++ 277

Surdéfinition des opérateurs (13)Surdéfinition des opérateurs (13)✔ Cas de l'opérateur << : exemple

istream& operator>>(istream& is, Point& pt){ is >> pt.x >> pt.y; return is;}

Page 278: Introduction à C++

Introduction à la programmation objet et générique avec C++ 278

Surdéfinition des opérateurs (14)Surdéfinition des opérateurs (14)✔ Surdéfinition des opérateurs : exercice

– Reprenez votre classe Vecteur3D• Modifiez cette classe en surdéfinissant l'opérateur

d'affectation (« = ») et l'opérateur d'égalité (« == »).• Remplacer la fonctions que vous avez précédemment fait

pour calculer la somme par la surcharge de l'opérateur « + ».

• Supprimez la fonction d'affichage que vous aviez précédemment réalisé et surdéfinissez les opérateurs « << » et « >> » avec les objets cout et cin pour votre classe Vecteur3D sur le modèle de ce qui a été fait pour la classe Point.

– On souhaite un affichage du type• <composante1, composante2, composante3>

Page 279: Introduction à C++

Introduction à la programmation objet et générique avec C++ 279

Conversion de types définies par l'utilisateur (1)Conversion de types définies par l'utilisateur (1)✔ CDU

– Le C++ permet de définir des conversions d'un type classe vers un autre type classe ou un type de base

• On parle de conversions définies par l'utilisateur (CDU)– Ces conversions pourront être mises en oeuvre implicitement

par le compilateur• Par exemple pour donner une signification à un appel de

fonction ou un opérateur– i.e. que si cette conversion n'était pas définie l'appel

de fonction ou l'opérateur serait illégal pour le compilateur.

– Pour définir des conversions, on peut définir 2 sortes de fonctions qui seront obligatoirement des fonctions membres

• Un constructeur à un argument• Un opérateur de cast

Page 280: Introduction à C++

Introduction à la programmation objet et générique avec C++ 280

Conversion de types définies par l'utilisateur (2)Conversion de types définies par l'utilisateur (2)✔ CDU avec un constructeur

– Un constructeur à un argument réalise une conversion du type de cet argument dans le type de sa classe, quel que soit le type de cet argument.

• Si l'on souhaite justement interdire la possibilité d'une conversion implicite, on ajoutera devant la déclaration du constructeur le mot-clé explicit

✔ CDU avec un opérateur de cast– Dans une classe A, on définira un opérateur de conversion

d'un type quelconque T (aussi bien un type de base qu'un autre type classe) en introduisant la fonction membre de prototype operator T ();

• Le type de la valeur de retour ne doit pas figurer dans l'en-tête ou le prototype d'une telle fonction.

• Le type de retour est obligatoirement défini par le nom de la fonction elle-même.

Page 281: Introduction à C++

Introduction à la programmation objet et générique avec C++ 281

Conversion de types définies par l'utilisateur (3)Conversion de types définies par l'utilisateur (3)✔ Règles d'utilisation des CDU

– Les CDU ne sont mis en oeuvre que si cela est nécessaire– Une seule CDU peut intervenir dans une chaîne de

conversions d'un argument d'une fonction ou d'un opérande d'un opérateur.

– Il ne doit pas y avoir d'ambiguïté• Plusieurs chaines de conversions ne doivent pas conduire

au même type, pour un argument ou un opérande donné.– Aucune conversion n'est réalisable sur un argument effectif en

cas de transmission par référence• Sauf si l'argument muet correspondant est déclaré avec

l'attribut const– Dans ce cas, on a les mêmes possibilités de

conversion qu'en cas de transmission par valeur.

Page 282: Introduction à C++

Introduction à la programmation objet et générique avec C++ 282

Conversion de types définies par l'utilisateur (4)Conversion de types définies par l'utilisateur (4)✔ Exemples

class CompteBancaire{ private : double solde; const double SOLDE_MINIMUM; mutable int nombreConsultations; static int nombre_comptes; public : CompteBancaire(); CompteBancaire(double s); CompteBancaire(double s, double solde_minimum); void deposer(double montant); void retirer(double montant); double donnerSolde() const; int getNombreConsultations() const; static int getNombreComptes(); operator double(); };

#include <cstdlib>#include <iostream>#include "CompteBancaire.h"using namespace std;int main(int argc, char *argv[]){ CompteBancaire c_b_1 = 100.0; cout << "Le solde : " << c_b_1.donnerSolde() << endl; double s = c_b_1; cout << "s = " << s << endl; system("PAUSE"); return EXIT_SUCCESS;}

//...CompteBancaire::CompteBancaire(double s) : SOLDE_MINIMUM(0.0){ this->solde = s; this->nombreConsultations = 0; CompteBancaire::nombre_comptes ++; }//... CompteBancaire::operator double(){ return solde;}

Page 283: Introduction à C++

Introduction à la programmation objet et générique avec C++ 283

L'héritage (1)L'héritage (1)✔ Rappels

– L'héritage est un mécanisme permettant le partage et la réutilisation de propriétés entre les objets.

– La relation d’héritage est une relation de généralisation / spécialisation.

• La classe parente est la superclasse (on utilise également l'expression « classe de base »), la classe qui hérite est la sous-classe (on utilise également l'expression « classe dérivée »).

– Avec l’héritage, il y a factorisation du code : on partage le code commun

• On écrit moins de code donc gain de place, diminution du risque d'erreur et du temps de développement.

• L'héritage est un puissant moyen d'organiser son code.• L'héritage est également une propriété fondamentale pour

implémenter le polymorphisme.

Page 284: Introduction à C++

Introduction à la programmation objet et générique avec C++ 284

L'héritage (2)L'héritage (2)✔ Représentation graphique de l'héritage

+seBattre()

Fantassin

+seBattre()

Cavalier

+lancerSort()#pointdeMagie

Magicien

+guerir()

Prêtre

+produire()

Paysan

+seBattre()+seNourrir()

Guerrier

+seNourrir()

#pointDeVie#force

Personnage

Page 285: Introduction à C++

Introduction à la programmation objet et générique avec C++ 285

L'héritage (3)L'héritage (3)✔ Héritage en C++

– Pour indiquer qu'une classe hérite d'une autre classe, il suffit de faire suivre le nom de la classe de « : » et du nom de la classe

#include "Personnage.h"class Guerrier : public Personnage{ public : Guerrier(); ~Guerrier(); void attaquer(); };

#include <string>#include "Random.h"using namespace std;class Personnage{ private : static Random generateur; static int nb_generateur; int points_vie; int points_force; int points_intelligence; int points_sagesse; public : Personnage(); ~Personnage(); string toString(); };

Guerrier.h

Personnage est la classe de base ou superclasse de Guerrier.Guerrier est la classe dérivée ou la sous-classe de Personnage

Personnage.h

Page 286: Introduction à C++

Introduction à la programmation objet et générique avec C++ 286

L'héritage (4)L'héritage (4)✔ Héritage et accès aux membres de classes (1/5)

– On ne peut pas accéder aux champs privés définis dans la classe de base depuis la classe dérivée

#include "Guerrier.h"Guerrier::Guerrier(){ if (nb_generateur == 0) generateur.initialise(); nb_generateur ++; points_vie = generateur.nextInt(1,10); points_force = generateur.nextInt(1,5); points_intelligence = generateur.nextInt(1,5); points_sagesse = generateur.nextInt(1,5); }//...

Guerrier.cpp

Génère des erreurs à la compilation

Page 287: Introduction à C++

Introduction à la programmation objet et générique avec C++ 287

L'héritage (5)L'héritage (5)✔ Héritage et accès aux membres de classes (2/5)

– Les membres privés d'une classe de base ne sont jamais accessibles aux fonctions membres de sa classe dérivée

• Outre les spécificateurs d'accès public et private, il existe un statut protégé défini avec le mot-clé protected

– Un membre protégé se comporte comme• un membre privé pour un utilisateur quelconque

de la classe ou de la classe dérivée,• un membre public pour la classe dérivée.

Page 288: Introduction à C++

Introduction à la programmation objet et générique avec C++ 288

L'héritage (6)L'héritage (6)✔ Héritage et accès aux membres de classes (3/5)

#include <string>#include "Random.h"using namespace std;class Personnage{ protected : static Random generateur; static int nb_generateur; int points_vie; int points_force; int points_intelligence; int points_sagesse; public : Personnage(); ~Personnage(); string toString(); };

#include "Personnage.h"class Guerrier : public Personnage{ public : Guerrier(); ~Guerrier(); void attaquer(); };

Personnage.h

Guerrier.h

Page 289: Introduction à C++

Introduction à la programmation objet et générique avec C++ 289

L'héritage (7)L'héritage (7)✔ Héritage et accès aux membres de classes (4/5)#include "Guerrier.h"Guerrier::Guerrier(){ if (nb_generateur == 0) generateur.initialise(); nb_generateur ++; points_vie = generateur.nextInt(1,20); points_force = generateur.nextInt(1,10); points_intelligence = generateur.nextInt(1,3); points_sagesse = generateur.nextInt(1,3); }//...

Ce code ne posera pas de problème à la compilation. Les attributs comme points_vie étant « protected » dans la classe de base.Par contre ces attributs restent inaccessibles depuis une autre classe ou une autre fonction.

Page 290: Introduction à C++

Introduction à la programmation objet et générique avec C++ 290

L'héritage (8)L'héritage (8)✔ Héritage et accès aux membres de classes : synthèse (5/5)

– public• Un membre public peut être utilisé n'importe où, même en

dehors de la classe elle-même– private

• Un membre privé ne peut être utilisé que depuis sa classe de déclaration

– protected • Un membre protégé ne peut être utilisé que depuis sa

classe de déclaration ou depuis l'une des classes dérivées de cette classe

Page 291: Introduction à C++

Introduction à la programmation objet et générique avec C++ 291

L'héritage (9)L'héritage (9)✔ Types de dérivation (1/3)

#include "Personnage.h"class Guerrier : public Personnage{ public : Guerrier(); ~Guerrier(); void attaquer(); }; Guerrier.h

Page 292: Introduction à C++

Introduction à la programmation objet et générique avec C++ 292

L'héritage (10)L'héritage (10)✔ Types de dérivation (2/3)

– En C++ il existe 3 types de dérivation• Publique

– Les membres de la classe de base conservent leur statut dans la classe dérivée.

• On parle de dérivation publique– Mot-clé : public

• Privée– Tous les membres de la classe de base deviennent

privés dans la classe dérivée.• On parle de dérivation privée

– Mot-clé : private• Protégée

– Les membres publics de la classe de base deviennent membres protégés de la classe dérivée ; les autres membres conservent leur statut.

• On parle de dérivation protégée– Mot-clé : protected

Page 293: Introduction à C++

Introduction à la programmation objet et générique avec C++ 293

L'héritage (11)L'héritage (11)✔ Types de dérivation (3/3)

– Lorsqu'un membre de classe est redéfini dans une classe dérivée, il reste toujours possible d'accèder aux membres de même nom de la classe de base

• Il suffit d'utiliser pour cela l'opérateur de résolution de portée « :: »

– Il faut bien sûr que l'accès à cette fonction soit autorisé.

• Ceci est possible tant pour les fonctions membres de la classe dérivée, que pour un client de cette classe dérivée.

Page 294: Introduction à C++

Introduction à la programmation objet et générique avec C++ 294

L'héritage (12)L'héritage (12)✔ Héritage et constructeurs (1/5)

– A chaque création d'un objet d'une classe, les constructeurs de toutes les superclasses de cette classe sont appelées afin de fournir une initialisation correcte des attributs hérités de l'objet.

• Les constructeurs sont appelés successivement dans la chaîne d'héritage, de la superclasse la plus élevée à la classe dérivée de plus bas-niveau.

– Soit il y a un appel au constructeur de la superclasse par défaut

– Soit on fournit lors de la définition du constructeur de la classe dérivée les éléments d'intialisation des classe de bases dans une liste placée entre la signature du constructeur et son corps

• Cette liste commence par deux points « : » et les éléments de la liste sont séparés par des virgules « , »

Page 295: Introduction à C++

Introduction à la programmation objet et générique avec C++ 295

L'héritage (13)L'héritage (13)✔ Héritage et constructeurs (2/5)

#include <sstream>#include <iostream>#include "Personnage.h"using namespace std;Random Personnage::generateur; int Personnage::nb_generateur = 0;int Personnage::numero_personnage = 0;Personnage::Personnage(){ if (nb_generateur == 0) generateur.initialise(); nb_generateur ++; numero_personnage ++; stringstream sstr; sstr << "personnage_" << numero_personnage ; name = sstr.str(); points_vie = generateur.nextInt(1,10); points_force = generateur.nextInt(1,5); points_intelligence = generateur.nextInt(1,5); points_sagesse = generateur.nextInt(1,5); }Personnage::Personnage(string name){ if (nb_generateur == 0) generateur.initialise(); nb_generateur ++; this->name = name; points_vie = generateur.nextInt(1,10); points_force = generateur.nextInt(1,5); points_intelligence = generateur.nextInt(1,5); points_sagesse = generateur.nextInt(1,5); }//...

#include <sstream>#include "Guerrier.h"int Guerrier::numero_guerrier = 0;Guerrier::Guerrier(){ Personnage::numero_personnage --; Guerrier::numero_guerrier ++; stringstream sstr; sstr << "guerrier_" << numero_guerrier ; name = sstr.str(); points_vie = generateur.nextInt(1,20); points_force = generateur.nextInt(1,10); points_intelligence = generateur.nextInt(1,3); points_sagesse = generateur.nextInt(1,3); }Guerrier::Guerrier(string name) : Personnage(name){ points_vie = generateur.nextInt(1,20); points_force = generateur.nextInt(1,10); points_intelligence = generateur.nextInt(1,3); points_sagesse = generateur.nextInt(1,3); } //...

Page 296: Introduction à C++

Introduction à la programmation objet et générique avec C++ 296

L'héritage (14)L'héritage (14)✔ Héritage et constructeurs (3/5)

– Si une classe de base ne comporte pas de constructeur par défaut, la classe dérivée doit toujours fournir un élément d'initialisation pour cette classe de base

• Elle doit faire appel explicitement à l'un des contructeurs de sa classe de base avec paramètres, le constructeur par défaut de cette dernière n'existant pas.

– On associe en général les éléments d'initialisation de classe de base et les initialisations des membres de données (syntaxe similaire).

Page 297: Introduction à C++

Introduction à la programmation objet et générique avec C++ 297

L'héritage (15)L'héritage (15)✔ Héritage et constructeurs (4/5) : cas du constructeur par

recopie– Si la classe dérivée ne possède pas de constructeur par

recopie, il y a appel du constructeur par recopie par défaut de cette classe, dont le fonctionnement est le suivant :

• Appel du constructeur par recopie de la superclasse– Soit celui qui a été défini, soit le constructeur par

recopie par défaut.• Initialisation des membres de données de la classe

dérivée qui ne sont pas héritées de la classe de base.

Page 298: Introduction à C++

Introduction à la programmation objet et générique avec C++ 298

L'héritage (16)L'héritage (16)✔ Héritage et constructeurs (5/5) : cas du constructeur par

recopie– Si la classe dérivée définit explicitement un constructeur par

recopie• Ce constructeur par recopie appelle le constructeur qui est

mentionné dans sa liste d'initialisation des classe de bases– Il peut s'agir du constructeur par recopie de la

superclasse ou d'un autre• Sinon, le constructeur par recopie appelle le constructeur

sans argument, si aucun constructeur de la classe de base n'est mentionné dans la liste d'initialisation.

– Dans ce cas il est donc nécessaireque la classe de base dispose d'un tel constructeur sans argument

• Sinon on a une erreur de compilation.

Page 299: Introduction à C++

Introduction à la programmation objet et générique avec C++ 299

L'héritage (17)L'héritage (17)✔ Conséquence de l'héritage (1/)

#include <cstdlib>#include <iostream>#include "Guerrier.h"using namespace std;int main(int argc, char *argv[]){ Personnage tab_perso[10]; Guerrier tab_guerrier[5]; int i; for(i=0; i < 10; i++) { cout << "un " << (i+1) << "eme personnage" << endl; cout << tab_perso[i].toString() << endl; } for(i=0; i < 5; i++) { cout << "un " << (i+1) << "eme guerrier" << endl; cout << tab_guerrier[i].toString() << endl; } Guerrier un_guerrier("Aragorn"); cout << "Un guerrier" << endl; cout << un_guerrier.toString() << endl; Personnage un_personnage; cout << "Un personnage" << endl; cout << un_personnage.toString() << endl; system("PAUSE"); return EXIT_SUCCESS;}

#include <string>#include "Random.h"using namespace std;class Personnage{ protected : static Random generateur; static int nb_generateur; static int numero_personnage; int points_vie; int points_force; int points_intelligence; int points_sagesse; string name; public : Personnage(); Personnage(string name); virtual ~Personnage(); virtual string toString(); };

#include "Personnage.h"class Guerrier : public Personnage{ private : static int numero_guerrier; public : Guerrier(); Guerrier(string name); virtual ~Guerrier(); virtual void attaquer(); };

Page 300: Introduction à C++

Introduction à la programmation objet et générique avec C++ 300

L'héritage (19)L'héritage (19)✔ Conséquence de l'héritage (2/)

– Si une fonction membre f() n'existe pas dans une classe dérivée B mais existe dans la classe de base A de cette classe B

• alors, d'invoquer la fonction f() sur un objet b de la classe B ne provoquera pas d'erreur

• C'est la fonction f() définie dans la classe A superclasse de B qui sera appelée

Page 301: Introduction à C++

Introduction à la programmation objet et générique avec C++ 301

L'héritage (20)L'héritage (20)✔ Opérateur d'affectation et héritage

– Considérons une classe dérivée B et sa classe de base A• Si la classe dérivée B n'a pas surdéfini l'opérateur

d'affectation (« = »), l'affectation de deux objets de type Bse déroule membre à membre

– On considère les attributs hérités de A constitue « un membre » traitée par l'affectation prévue dans la classe A.

– Les autres membres subissent l'affectation prévue pour leur type (par défaut ou surdéfinie, sont les cas)

• Si la classe dérivée B a surdéfini l'opérateur d'affectation, l'affectation de 2 objets de type B fera appel à l'opérateur d'affectation définie dans B.

– L'opérateur d'affectation de A ne sera pas appelé, même s'il a été surdéfini dans A.

– L'opérateur d'affectation de B doit prendre en charge tout ce qui concerne l'affectation d'objets de type B, y compris ce qui concerne les membres héritées de A.

Page 302: Introduction à C++

Introduction à la programmation objet et générique avec C++ 302

L'héritage (21)L'héritage (21)✔ Polymorphisme (1/3)

– Polymorphisme : capacité pour une entité de prendre plusieurs formes

#include <cstdlib>#include <iostream>#include "Guerrier.h"using namespace std;int main(int argc, char *argv[]){ Guerrier un_guerrier("Aragorn"); cout << "Un guerrier" << endl; cout << un_guerrier.toString() << endl; Personnage un_personnage; cout << "Un personnage" << endl; cout << un_personnage.toString() << endl; un_personnage = un_guerrier; cout << "un_personnage après l'affectation d'un objet guerrier" << endl; cout << un_personnage.toString() << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 303: Introduction à C++

Introduction à la programmation objet et générique avec C++ 303

L'héritage (22)L'héritage (22)✔ Polymorphisme (2/3)

– On peut mettre un objet d'un type dérivé dans un objet d'un type de base

• Ainsi dans l'exemple précédent l'affectation « un_personnage = un_guerrier; » est légale.

– Elle revient à convertir l'objet « un_guerrier » dans le type Personnage

• Logique : après tout un objet de type Guerrierest aussi un objet de type Personnage.

• L'affectation dans l'autre sens est illégale.– De même, on peut mettre un pointeur sur un objet d'un type

dérivé dans un pointeur sur un objet d'une classe de base correspondante.

• L'affectation dans l'autre sens est illégale mais peut être forcée avec du transtypage (fortement déconseillé)

Page 304: Introduction à C++

Introduction à la programmation objet et générique avec C++ 304

L'héritage (23)L'héritage (23)✔ Polymorphisme (3/3)

#include <cstdlib>#include <iostream>#include "Guerrier.h"using namespace std;int main(int argc, char *argv[]){ // ... Guerrier *g = new Guerrier; cout << "Un pointeur sur guerrier" << endl; cout << g->toString() << endl; Personnage *p = new Personnage; cout << "Un pointeur sur personnage" << endl; cout << p->toString() << endl; p = g; cout << "p après l'affectation du pointeur g" << endl; cout << p->toString() << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 305: Introduction à C++

Introduction à la programmation objet et générique avec C++ 305

L'héritage (24)L'héritage (24)✔ Fonctions membres virtuelles (1/5)

– Pour définir un nouveau comportement d'une fonction membre héritée d'une classe de base dans une classe dérivée, il faut la redéfinir

• La redéfinition ne doit pas être confondu avec la surcharge• Il s'agit ici de spécifier un comportement nouveau pour une

fonction membre dans la classe dérivée.– Pour qu'une fonction membre puisse être redéfinie, elle doit

être déclarée avec le mot-clé virtual dans la classe de base.

• La fonction membre correspondante dans la classe dérivée doit être déclarée comme toute autre fonction membre, bien qu'il soit d'usage de la déclarer également avec le mot-clé virtual pour rendre le code plus clair et plus explicite.

Page 306: Introduction à C++

Introduction à la programmation objet et générique avec C++ 306

L'héritage (25)L'héritage (25)✔ Fonctions membres virtuelles (2/5)

#include <string>#include "Random.h"using namespace std;class Personnage{ protected : static Random generateur; static int nb_generateur; static int numero_personnage; int points_vie; int points_force; int points_intelligence; int points_sagesse; string name; public : Personnage(); Personnage(string name); Personnage(const Personnage &p); virtual ~Personnage(); virtual string toString(); Personnage& operator=(const Personnage &p);};

#include "Personnage.h"class Guerrier : public Personnage{ protected : static int numero_guerrier; public : Guerrier(); Guerrier(string name); virtual ~Guerrier(); virtual string toString(); virtual void attaquer(); };

Page 307: Introduction à C++

Introduction à la programmation objet et générique avec C++ 307

L'héritage (25)L'héritage (25)✔ Fonctions membres virtuelles (3/5)

– Lorsque la fonction membre virtuelle est appelée à partir d'un pointeur sur la classe de base ou d'une référence sur la classe dérivée, le C++ utilise l'association dynamique pour déterminer quelle fonction membre appeler.

• Ce choix est effectué à l'exécution et non à la compilation du programme, en fonction du type réel du pointeur sur la classe de base ou de la référence.

– Attention• L'autorisation d'appeler une fonction membre est délivrée

ou non, selon son spécificateur d'accès, lors de la compilation.

• Or le choix de la fonction à appeler dans une telle situation de polymorphisme est effectué à l'exécution

– Il est donc possible d'appeler une fonction membre depuis un point non autorisé par le spécificateur d'accès de cette fonction membre si celui de la fonction membre correspondante dans la classe de base l'autorise.

Page 308: Introduction à C++

Introduction à la programmation objet et générique avec C++ 308

L'héritage (26)L'héritage (26)✔ Fonctions membres virtuelles (4/5)

– Un constructeur ne peut pas être virtuel, alors qu'un destructeur peut l'être

• Il est même fortement recommandé que les destructeurs soient déclarés comme virtuels

– Le fait de déclarer une fonction membre d'une classe de base comme virtuelle, n'impose pas qu'elle soit redéfinie dans toute classe dérivée, sauf si elle a été déclarée virtuelle pure.

– Dès qu'une fonction membre est déclarée virtuelle dans une classe de base, elle est virtuelle pour tout le reste de la chaîne d'héritage.

– La liste de paramètres et le type de retour de la fonction membre dans les classes dérivées doivent correspondre à ceux de la classe de base.

• Sinon, la fonction membre de la classe dérivée occulte la fonction membre de la classe de base et il n'y a pas polymorphisme

Page 309: Introduction à C++

Introduction à la programmation objet et générique avec C++ 309

L'héritage (27)L'héritage (27)✔ Fonctions membres virtuelles (5/5)

– Si une fonction n'est pas déclarée avec le mot-clé virtualdans la classe de base, la même fonction membre dans une classe dérivée cache celle de la classe de base et il n'y a pas de polymorphisme.

– Une fonction membre virtuelle déclarée comme privée dans la classe de base peut être redéfinie dans une classe dérivée même si elle ne peut pas être appelée depuis la classe dérivée.

• Un appel à cette fonction membre depuis la classe de base utilise le comportement polymorphique et la fonction membre de la classe dérivée concernée est bien appelée

Page 310: Introduction à C++

Introduction à la programmation objet et générique avec C++ 310

L'héritage (28)L'héritage (28)✔ Polymorphisme et fonctions virtuelles : synthèse (1/2)

– Le polymorphisme désigne la capacité pour une entité de prendre plusieurs formes

• En C++ (ou en Java) on parle de polymorphisme d'héritage

– dans une variable d'une certaine classe ou dans une variable pointeur sur une certaine classe, on peut mettre indifféremment des objets ou des pointeurs de cette classe ou de l'une de ces sous-classes

Page 311: Introduction à C++

Introduction à la programmation objet et générique avec C++ 311

L'héritage (29)L'héritage (29)✔ Polymorphisme et fonctions virtuelles : synthèse (2/2)

– Le polymorphisme rend possible l'utilisation d'une même instruction pour appeler dynamiquement des méthodes différentes dans la hiérarchie des classes.

• Le choix de la fonction a appelé est résolu au moment de l'exécution, selon le type réel de l'objet concerné.

• On parle de typage dynamique des objets ou de ligature dynamique de fonctions

– En C++, le polymorphisme est mis en oeuvre par l'utilisation des fonctions virtuelles.

• Mot-clé : virtual

Page 312: Introduction à C++

Introduction à la programmation objet et générique avec C++ 312

L'héritage (30)L'héritage (30)✔ Destructeurs et héritage (1/3)

– A chaque destruction d'un objet d'une sous-classe, une série de destructeurs est appelée afin que chaque classe dans la chaîne d'héritage puisse effectuer les opérations de nettoyage nécessaire.

– Les destructeurs sont appelés successivement dans la chaîne d'héritage, de la classe dérivée de plus bas niveau à la superclasse la plus élevée.

• Lorsqu'un objet est détruit il est impératif que tous les destructeurs de la chaîne d'héritage puissent être appelés.

• Pour se faire, le destructeur de la classe de base doit être déclaré à l'aide du mot-clé virtual.

Page 313: Introduction à C++

Introduction à la programmation objet et générique avec C++ 313

L'héritage (31)L'héritage (31)✔ Destructeurs et héritage (2/3)

– Le fait de ne pas déclarer le destructeur d'une classe comme étant virtual est une erreur fréquente, source de fuites de mémoire et de comportements imprévus.

• En effet lorsque des sous-classes sont par la suite créées, seul le destructeur de la classe du pointeur est appelé et le comportement polymoprhique que l'on est en droit d'attendre n'a pas lieu.

Page 314: Introduction à C++

Introduction à la programmation objet et générique avec C++ 314

L'héritage (32)L'héritage (32)✔ Destructeurs et héritage (3/3)

#include <string>#include "Random.h"using namespace std;class Personnage{ protected : static Random generateur; static int nb_generateur; static int numero_personnage; int points_vie; int points_force; int points_intelligence; int points_sagesse; string name; public : Personnage(); Personnage(string name); Personnage(const Personnage &p); virtual ~Personnage(); virtual string toString(); Personnage& operator=(const Personnage &p);};

Page 315: Introduction à C++

Introduction à la programmation objet et générique avec C++ 315

L'héritage (33)L'héritage (33)✔ Classe de base abstraite (1/3)

– Une classe de base abstraite est une classe comportant une ou plusieurs fonctions membres virtuelles pures.

• Une fonction membre est virtuelle pure lorsqu'elle est déclarée avec le mot clé virtual et lorsqu'elle comporte dans la définition de la classe le suffixe « =0 » dans sa signature.

class Mammal{ protected : int age; public : Mammal(); virtual ~Mammal(); virtual void manger()=0;};

La classe Mammal estune classe abstraite

Page 316: Introduction à C++

Introduction à la programmation objet et générique avec C++ 316

L'héritage (34)L'héritage (34)✔ Classe de base abstraite (2/3)

– Une classe contenant une ou plusieurs fonctions membres virtuelles pures ne peut pas être instanciée.

– Une classe dérivée d'une classe abstraite doit • comporter les fonctions membres virtuelles pures de sa

classe de base ou bien

• déclarer à son tour ces fonctions membres virtuelles pures– Une fonction déclarée virtuelle pure dans une classe

de base peut ne pas être déclarée dans une classe dérivée

• Dans ce cas elle est à nouveau implicitement fonction virtuelle pure dans cette classe dérivée.

Page 317: Introduction à C++

Introduction à la programmation objet et générique avec C++ 317

L'héritage (35)L'héritage (35)✔ Classe de base abstraite (3/3)

#include <cstdlib>#include <iostream>#include "Homme.h"using namespace std;int main(int argc, char *argv[]){ //Mammal m; provoquerait une erreur à la compilation Mammal *m; // Avec un pointeur cela passe m = new Homme; // j'affecte à mon pointeur sur Mammal, un pointeur sur Homme m->manger(); //appelle la fonction manger de Homme system("PAUSE"); return EXIT_SUCCESS;}class Mammal{ protected : int age; public : Mammal(); virtual ~Mammal(); virtual void manger() =0;};

#include "Mammal.h"class Homme : public Mammal{ public : Homme(); virtual ~Homme(); virtual void manger(); };

Page 318: Introduction à C++

Introduction à la programmation objet et générique avec C++ 318

L'héritage (36)L'héritage (36)✔ Héritage multiple (1/9)

– Il y a certaines situations dans lesquelles quand on conçoit les classes de notre application, on souhaiterait qu'une même classe hérite de propriétés de 2 classes différentes.

#Nom#Prenom#Age#NumSS

Personne

#SalaireSalarie

#NumEtudiantEtudiant

EtudiantSalarie

Page 319: Introduction à C++

Introduction à la programmation objet et générique avec C++ 319

L'héritage (37)L'héritage (37)✔ Héritage multiple (2/9)

– En C++, l'héritage multiple est autorisée (contrairement à Java par exemple où il est impossible).

• Une classe peut hériter de plusieurs autres classes– On procède de manière similaire à l'héritage simple

mais on fournit après les deux points « : » une liste de classes de base

– Chaque nom de classe de base peut être précédé d'un spécificateur d'accès pour l 'héritage publique, privée ou protégée

– Les modalités d'accès aux membres de chacune des classes de base restent les mêmes que dans le cas d'une dérivation simple.

Page 320: Introduction à C++

Introduction à la programmation objet et générique avec C++ 320

L'héritage (38)L'héritage (38)✔ Héritage multiple (3/9)

class Personne{ //... };class Etudiant : public Personne{ //... };class Salarie : public Personne{ //... };class EtudiantSalarie : public Etudiant, public Salarie{ //... };

Page 321: Introduction à C++

Introduction à la programmation objet et générique avec C++ 321

L'héritage (39)L'héritage (39)✔ Héritage multiple (4/9)

– L'opérateur de résolution de portée peut être utilisé• Lorsque l'on veut accéder à un membre d'une des classes

de base, lorsque ce membre a été redéfini dans la classe dérivée

– On pouvait également le faire dans le cas de l'héritage simple

• Lorsque deux classes de base possèdent un membre de même nom et qu'il faut alors préciser celui que l'on veut invoquer.

Page 322: Introduction à C++

Introduction à la programmation objet et générique avec C++ 322

L'héritage (40)L'héritage (40)✔ Héritage multiple (5/9) : Constructeur et destructeur

– La création d'un objet entraîne l'appel du constructeur de chacune des classes de base, dans l'ordre où ces classes sont mentionnées dans la déclaration de la classe dérivée

• Dans l'exemple précédent le constructeur de Etudiant sera appelé avant le constructeur de Salarie, pour la création d'un Objet de la classe EtudiantSalarie.

– De manière similaire, lors de la destruction d'un objet, il y a appel des destructeurs, mais qui sont appelés dans l'ordre inverse où les classes sont mentionnées dans la déclaration de la classe dérivée.

• Dans l'exemple précédent le destructeur de Salarie sera appelé avant le destructeur d'Etudiant lors de la destruction d'un Objet de la classe EtudiantSalarie.

– Comme dans le cas de l'héritage simple, on peut mentionner dans la liste d'initialisation du constructeur de la classe dérivée des informations à transmettre à chacun des constructeurs des classes de base.

Page 323: Introduction à C++

Introduction à la programmation objet et générique avec C++ 323

L'héritage (41)L'héritage (41)✔ Héritage multiple (6/9) : classes virtuelles (1)

– Par le biais de dérivations successives, il est tout à fait possible qu'une classe hérite 2 fois d'une même classe

• C'est le cas dans l'exemple de la classe EtudiantSalarie qui hérite 2 fois de la classe Personne, via ses 2 superclasses directes.

• Dans un cas comme celui-ci, les membres données de la superclasse en question (Personne dans l'exemple) apparaissent 2 fois dans sa descendante (EtudiantSalarie).

– Il peut alors être nécessaire de faire appel à l'opérateur de résolution de portée (::) pour lever l'ambiguïté.

– Si l'on souhaite que les membres n'apparaissent qu'une fois dans la classe dérivée de « second niveau », il faut dans les déclarations des classes dérivées de premier niveau (dans l'exemple précédent Etudiant et Salarie) déclarer avec le mot-clé virtual la classe dont on souhaite éviter la duplication (dans l'exemple la classe Personne).

Page 324: Introduction à C++

Introduction à la programmation objet et générique avec C++ 324

L'héritage (42)L'héritage (42)✔ Héritage multiple (7/9) : classes virtuelles (2)

#include <string>class Personne{ protected : string nom; string prenom; string numSS; int age; };class Etudiant : public virtual Personne{ protected : string numEtudiant; };class Salarie : public virtual Personne{ protected : double salaire; };class EtudiantSalarie : public Etudiant, public Salarie{ };

Page 325: Introduction à C++

Introduction à la programmation objet et générique avec C++ 325

L'héritage (43)L'héritage (43)✔ Héritage multiple (8/9) : classes virtuelles (3)

– Lorsqu'il y a une classe virtuelle qui est déclarée, il faut que les constructeurs des éventuelles classes dérivées puissent préciser les informations à transmettre au constructeur de cette classe virtuelle.

• Il faut donc dans ce cas préciser dans l'en-tête du constructeur la classe dérivée, en plus des arguments destinés aux constructeurs des superclasses immédiates, les arguments à passer au constructeur de la superclasse virtuelle.

• De plus, dans ce cas, les constructeurs des classes qui ont déclarés leur superclasse virtuelle n'auront plus à spécifier d'informations pour un constructeur de la super classe virtuelle.

– Le constructeur de la classe virtuelle est toujours appelée avant les autres.

– Attention à ne pas confondre classe virtuelle et classe abstraite, ce sont 2 concepts différents.

Page 326: Introduction à C++

Introduction à la programmation objet et générique avec C++ 326

L'héritage (44)L'héritage (44)✔ Héritage multiple (9/9) : classes virtuelles (4)

EtudiantSalarie::EtudiantSalarie(string numEtudiant, double salaire, string nom, string prenom, int age, string numSS):Salarie(salaire), Etudiant(numEtudiant), Personne(nom,prenom,age,numSS){}

Page 327: Introduction à C++

Introduction à la programmation objet et générique avec C++ 327

Les espaces de noms (1)Les espaces de noms (1)✔ Intérêts

– Un espace de nom définit une portée avec un nom. • Rappel : la portée d'un objet est la région du programme

dans laquelle l'objet peut être utilisé.– Exemple de portées :

• Un bloc, un corps de fonction, tout le programme, etc.

• Un espace de nom est utilisé – pour regrouper des noms portant sur une même

thématique– Pour éviter des « collisions » avec des noms

identiques dans différentes parties du programme et relevant de thématiques différentes.

– Mot-clé : namespacenamespace MonEspacedeNoms{ //....}

Page 328: Introduction à C++

Introduction à la programmation objet et générique avec C++ 328

Les espaces de noms (2)Les espaces de noms (2)✔ Utilisation (1/2)

– Un espace de noms peut contenir tout ce qu'il est possible de déclarer en dehors de tout espace de noms

• classes, fonctions, autres espaces de noms, ...– Les espaces de noms sont des éléments « ouverts »

• Il est possible de les enrichir à l'aide de déclarations multiples

namespace MonEspacedeNoms{ //....} //...namespace MonEspacedeNoms{ //....}

Page 329: Introduction à C++

Introduction à la programmation objet et générique avec C++ 329

Les espaces de noms (3)Les espaces de noms (3)✔ Utilisation (2/2)

– Un espace de noms est simplement le nom donnée à une portée

• C'est l'espace regroupant tous les noms des objets dans cette portée.

– Pour utiliser un nom de classe, de variable, de fonction, etc. en dehors de l'espace de nom dans lequel il est déclaré, il suffit d'utiliser l'opérateur de résolution de portée « :: ».

• Pour définir une fonction en dehors de son espace de noms, on procède de la même manière en utilisant l'opérateur de portée

– C'est très similaire à la manière dont on procède pour déclarer une fonction membre en dehors de sa classe

Page 330: Introduction à C++

Introduction à la programmation objet et générique avec C++ 330

Les espaces de noms (4)Les espaces de noms (4)✔ Typologie

– On distingue• L'espace de noms global

– Il a un nom vide– Il regroupe tous les objets déclarés en dehors de tout

autre espace de noms• Les variables globales par exemple appartiennent

à cet espace de noms• Les espaces de noms explicitement nommés

– Ceux que l'on créé• Les espaces de nom non nommés

– Ils n'ont pas de nom, même pas un nom vide• Par exemple les blocs qui suivent une boucle.

Page 331: Introduction à C++

Introduction à la programmation objet et générique avec C++ 331

Les espaces de noms (5)Les espaces de noms (5)✔ Espace de nom standard

– La bibliothèque standard C++ comporte un espace de noms std

• Cela permet de de distinguer la version standardisée des nouvelles fonctionnalités de la bibliothèque de celles apparues avant la standardisation.

– Ainsi, tous les fichiers d'entête de la bibliothèque standard placent leur contenu dans l'espace de noms std, pour éviter des conflits avec les versions de ces fichiers antérieures à la standardisation.

Page 332: Introduction à C++

Introduction à la programmation objet et générique avec C++ 332

Les espaces de noms (6)Les espaces de noms (6)✔ Déclarations using

– Une déclaration using permet d'utiliser un nom précis d'un espace de noms donnés sans avoir à le qualifier

• Une telle déclaration using ajoute un nom à la portée du code comportant cette déclaration

– une erreur de compilation se produit si ce nom est déclaré ailleurs avec la même portée;

– Le nom en provenance de l'espace de noms masque toute autre entité de même nom dans une portée plus élevée.

namespace MonEspacedeNoms{ double une_fonction(); //...} //...using MonEspacedeNoms::une_fonction();//...double res = une_fonction();

Page 333: Introduction à C++

Introduction à la programmation objet et générique avec C++ 333

Les espaces de noms (7)Les espaces de noms (7)✔ Directives using

– Une directive using permet d'utiliser tous les noms d'un espace de noms donné sans avoir à les qualifier

• De la forme : using namespace <nom_espace> ;• Par exemple le « using namespace std; »

– Une directive using n'ajoute pas le nom à la portée courante• Elle permet d'avoir accès à des noms en dehors de la

portée• Si le nom correspondant est déclaré ailleurs avec la portée

locale, le nom en provenance de l'espace de noms est masqué dès que le code arrive à la déclaration locale ;

• Le nom en provenance de l'espace de nom masque toute autre entité de même nom dans une portée plus élevée.

• Une erreur de compilation se produit si ce nom est visible depuis plusieurs espaces de noms ou si le nom en provenance de l'espace de noms explicite masque le même nom de l'espace de noms global.

Page 334: Introduction à C++

Introduction à la programmation objet et générique avec C++ 334

Les espaces de noms (8)Les espaces de noms (8)✔ Espace de noms anonyme

– Un espace de noms est anonyme si sa déclaration ne précise aucun nom.

– Les noms dans un tel espace de noms ont une portée de fichier

• Ils se comportent comme des variables ou des fonctions statiques sans avoir à utiliser explicitement le mot-clé static pour chacun d'eux.

– Un espace de noms anonyme ne pouvant être identifié, une directive using implicite a lieu après sa déclaration.

– L'utilisation d'espaces de noms anonymes est recommandée pour déclarer des variables et fonctions ayant une portée de fichier.

✔ Remarque– Un espace de noms n'est pas une structure, une classe ou un

objet, c'est juste un nom de regroupement, une étiquette.

Page 335: Introduction à C++

Introduction à la programmation objet et générique avec C++ 335

Plan général du coursPlan général du cours✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques

• Livre• Web

– Les outils utilisés dans ce cours✔ Introduction aux concepts de la programmation orientée

objet– Conception et « Orienté Objet »– Les cartes CRC

✔ Introduction au C++– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 336: Introduction à C++

Introduction à la programmation objet et générique avec C++ 336

Programmation générique en C++

Page 337: Introduction à C++

Introduction à la programmation objet et générique avec C++ 337

Introduction au C++ (3/4) : sommaireIntroduction au C++ (3/4) : sommaire✔ Introduction au C++

– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 338: Introduction à C++

Introduction à la programmation objet et générique avec C++ 338

IntroductionIntroduction✔ Notion de Patron

– En anglais on utilise le terme template pour parler des patrons• On parle aussi parfois de classes paramétrées pour

désigner des patrons de classe– Les patrons sont des modèles à partir desquels des classes

ou des fonctions peuvent être générées automatiquement par le compilateur d'après une série de paramètres

• A chaque fois qu'un patron est utilisé avec une série de paramètres différents, une nouvelle version de la classe ou de la fonction est créée

– On dit aussi parfois que l'on « instancie » une nouvelle version de la classe ou de la fonction.

• Chacune de ces nouvelles versions correspond à une spécialisation du patron.

– A partir d'une unique définition comportant des paramètres de type, on décrit une famille de classes ou de fonctions.

Page 339: Introduction à C++

Introduction à la programmation objet et générique avec C++ 339

Fonctions patrons (1)Fonctions patrons (1)✔ Exemple introductif

#include <cstdlib>#include <iostream>#include <string>using namespace std;template <class Type> void echanger(Type &x, Type &y){ Type temp = x; x = y; y = temp; };int main(int argc, char * argv[]){ int a,b; string s1,s2; cout << "entrer 2 valeurs entieres pour a et b" << endl; cin >> a >> b; cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; cout << " permutation de a et b" << endl; echanger(a,b); cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 340: Introduction à C++

Introduction à la programmation objet et générique avec C++ 340

Fonctions patrons (2)Fonctions patrons (2)✔ Définition en C++ (1/2)

– Pour paramétrer une fonction patron, sa déclaration et sa définition doivent être précédées du mot clé template.

• Les paramètres du patrons suivent dans une liste entourée des signes inférieur et supérieur

• Les paramètres de type sont précédés des mots-clés class ou typename.

– Ces paramètres sont utilisés à la place de types spécifiques au sein de la définition de la fonction.

template <class Type> void echanger(Type &x, Type &y){ Type temp = x; x = y; y = temp; };

Page 341: Introduction à C++

Introduction à la programmation objet et générique avec C++ 341

Fonctions patrons (3)Fonctions patrons (3)✔ Définition en C++ (2/2)

– Dans l'exemple, la fonction patron utilise un seul paramètre de type nommé Type.

• Elle sert de « modèle », de « patron » à toute fonction échangeant 2 valeurs de même type.

template <class Type> void echanger(Type &x, Type &y){ Type temp = x; x = y; y = temp; };

Page 342: Introduction à C++

Introduction à la programmation objet et générique avec C++ 342

Fonctions patrons (4)Fonctions patrons (4)✔ Instanciations des fonctions patrons

– Le complilateur crée automatiquement une instance correcte de la fonction patron selon les types des paramètres utilisés lors de son appel.

– Une fonction patron est appelée de la même manière que qu'une fonction « normale »

//...template <class Type> void echanger(Type &x, Type &y);int main(int argc, char * argv[]){ int a,b; string s1,s2; cout << "entrer 2 valeurs entieres pour a et b" << endl; cin >> a >> b; cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; cout << " permutation de a et b" << endl; echanger(a,b); cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; cout << "entrer 2 chaines de caracteres pour s1 et s2" << endl; cin >> s1 >> s2; cout << " valeur dans s1 : " << s1 << " ; valeur dans s2 : " << s2 << endl; cout << " permutation de s1 et s2" << endl; echanger(s1,s2); cout << " valeur dans s1 : " << s1 << " ; valeur dans s2 : " << s2 << endl; system("PAUSE"); return EXIT_SUCCESS;} //...

Page 343: Introduction à C++

Introduction à la programmation objet et générique avec C++ 343

Fonctions patrons (5)Fonctions patrons (5)✔ Paramètres de fonctions patrons

– Les fonctions patrons peuvent prendre des classes patrons comme paramètres

• Nous verrons un exemple plus loin, au niveau des explications sur les classes patrons

Page 344: Introduction à C++

Introduction à la programmation objet et générique avec C++ 344

Fonctions patrons (6)Fonctions patrons (6)✔ Spécialisation explicite de fonctions patrons (1/2)

– Une spécialisation explicite d'une fonction patron définit un modèle spécifique de fonction à utiliser pour un jeu de paramètres donné.

• On utilise le mot-clé template suivi des symboles inférieur et supérieur : template <>

• Puis après le nom de la fonction, la série de paramètres pour laquelle la spécialisation s'effectue, toujours entre les symboles inférieur et supérieur

– Par exemple si on veut spécialiser la fonction echanger pour des objets string

• void echanger<string>(string &s1, string &s2)

• Cette spécialisation définit la forme de la fonction patron echanger à utiliser en priorité pour des objets string passés en paramètre

– Il est possible de définir un nombre illimité de spécialisations explicites redéfinissant une fonction patron

Page 345: Introduction à C++

Introduction à la programmation objet et générique avec C++ 345

Fonctions patrons (7)Fonctions patrons (7)✔ Spécialisation explicite de fonctions patrons (2/2) : Exemple

//...template <class Type> void echanger(Type &x, Type &y){ Type temp = x; x = y; y = temp; };template<> void echanger<string>(string &s1, string &s2){ s1.swap(s2); };int main(int argc, char * argv[]){ int a,b; string s1,s2; cout << "entrer 2 valeurs entieres pour a et b" << endl; cin >> a >> b; cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; cout << " permutation de a et b" << endl; echanger(a,b); cout << " valeur dans a : " << a << " ; valeur dans b : " << b << endl; cout << "entrer 2 chaines de caracteres pour s1 et s2" << endl; cin >> s1 >> s2; cout << " valeur dans s1 : " << s1 << " ; valeur dans s2 : " << s2 << endl; cout << " permutation de s1 et s2" << endl; echanger(s1,s2); //appel le echanger specifique aux chaines cout << " valeur dans s1 : " << s1 << " ; valeur dans s2 : " << s2 << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 346: Introduction à C++

Introduction à la programmation objet et générique avec C++ 346

Fonctions patrons (8)Fonctions patrons (8)✔ Paramètres non types des fonctions patrons

– Ces paramètres non types sont des valeurs constantes utilisées dans la définition de la fonction

• Les paramètres non types comportent un type suivi d'un nom

• La valeur des paramètres non-types doit être constante• Le type de l'un de ces paramètres non type peut être le

suivant :– Entier– Énumération– Pointeur sur membre– Pointeur– Référence

• Dans ces 3 derniers cas, il faut que les pointeurs ou les références correspondent à des objets ou des fonctions avec une édition de liens externes

– Nous verrons un exemple avec les patrons de classe

Page 347: Introduction à C++

Introduction à la programmation objet et générique avec C++ 347

Classes patrons (1)Classes patrons (1)✔ Exemple introductif

– Dans cet exemple on définit une classe Tableaureprésentant des tableaux pouvant contenir des éléments de tout type.

template <class Type> class Tableau{ private : Type *elements; int taille; public : Tableau(); Tableau(int taille); ~Tableau(); bool inserer(const Type &element, int pos); Type getElement(int index); void setTaille(int taille); int getTaille(); }; //...

Page 348: Introduction à C++

Introduction à la programmation objet et générique avec C++ 348

Classes patrons (2)Classes patrons (2)✔ Définition

– Pour définir une classe patron, sa déclaration doit être précédée du mot-clé template

• Les paramètres du patron suivent ce mot-clé dans une liste entourée des signes inférieur et supérieur

– Les paramètres du patron sont la plupart du temps des types mais pas uniquement !

• Les paramètres de type sont précédés des mots-clés class ou typename.

– template <class Type> class Tableau• Ces paramètres sont utilisés à la place de type spécifique

au sein de la définition de la classe. – Type *elements;– Type getElement(int index);

Page 349: Introduction à C++

Introduction à la programmation objet et générique avec C++ 349

Classes patrons (3)Classes patrons (3)✔ Définition des fonctions membres

– Attention• la définition des fonctions membres doit avoir lieu dans le

fichier en-tête de la classe patron– Les fonctions membres définies en dehors de la déclaration

de leur classe patron doivent également comporter les paramètres précédés du mot-clé template

//...template <class Type> Tableau<Type>::Tableau(int taille){ this->taille = taille; elements = new Type[this->taille]; }//... template <class Type> bool Tableau<Type>::inserer(const Type &element, int pos){ if ( (pos >= 0) && (pos < taille)) { elements[pos] = element; return true; } return false; } //...

Page 350: Introduction à C++

Introduction à la programmation objet et générique avec C++ 350

Classes patrons (4)Classes patrons (4)✔ Note pour les déclarations et les définitions

– On peut utiliser un patron de classe pour définir un autre patron de classe notamment...

– A chaque fois que des patrons sont imbriqués de telle sorte que les crochets se suivent (par exemple >> ou <<), un espace doit être inséré entre ces signes pour éviter toute ambiguïté avec les opérateurs de décalage de bits

• On utilise donc > > et < < à la place de >> et <<

Page 351: Introduction à C++

Introduction à la programmation objet et générique avec C++ 351

Classes patrons (5)Classes patrons (5)✔ Instanciation de classes patrons (1/2)

– Pour instancier une classe patron, il faut préciser les paramètres de la classe patron en plus de son nom partout où elle est utilisée

• Les paramètres sont placés dans une liste entourée des signes inférieur et supérieur après le nom de la classe

• Une fois une classe patron instanciée, elle peut être manipulée comme tout autre classe.

Page 352: Introduction à C++

Introduction à la programmation objet et générique avec C++ 352

Classes patrons (6)Classes patrons (6)✔ Instanciation de classes patrons (2/2)#include "Tableau.h"using namespace std;int main(int argc, char *argv[]){ Tableau<int> tab1(5); Tableau<double> tab2(7); int i; for(i = 0 ; i < tab1.getTaille(); i++) {tab1.inserer(0,i);} for(i = 0 ; i < tab2.getTaille(); i++) {tab2.inserer(1.5,i); } for(i = 0 ; i < tab1.getTaille(); i++) {cout << tab1.getElement(i) << " ";} cout << endl; for(i = 0 ; i < tab2.getTaille(); i++) {cout << tab2.getElement(i) << " ";} cout << endl; system("PAUSE"); return EXIT_SUCCESS;}

Page 353: Introduction à C++

Introduction à la programmation objet et générique avec C++ 353

Classes patrons (6)Classes patrons (6)✔ Spécialisation explicite d'une classe patron (1/2)

– Une spécialisation explicite d'une classe patron définit un modèle spécifique de classe à utiliser pour un jeu de paramètres donné.

• Il faut utiliser le mot-clé template suivi des signes inférieur et supérieur, puis le nom de la classe, suivi lui-même de la série de paramètres pour laquelle la spécialisation doit s'effectuer.

Page 354: Introduction à C++

Introduction à la programmation objet et générique avec C++ 354

Classes patrons (7)Classes patrons (7)✔ Spécialisation explicite d'une classe patron (2/2)

template <> class Tableau<string>{ private : string *elements; int taille; public : Tableau(); Tableau(int taille); ~Tableau(); bool inserer(const string &element, int pos); string getElement(int index); void setTaille(int taille); int getTaille(); }; //...

Page 355: Introduction à C++

Introduction à la programmation objet et générique avec C++ 355

Classes patrons (8)Classes patrons (8)✔ Paramètres non types des classes patrons (1/3)

– Les paramètres non types sont des valeurs constantes utilisées dans la définition de la classe

• Les paramètres non types comportent un type suivi d'un nom.

template <class Type, int n> class Tableau{ private : Type elements[n]; public : Tableau(); ~Tableau(); bool inserer(const Type &element, int pos); Type getElement(int index); };

Page 356: Introduction à C++

Introduction à la programmation objet et générique avec C++ 356

Classes patrons (9)Classes patrons (9)✔ Paramètres non types des classes patrons (2/3)

– La valeur des paramètres non types est fixée lors de l'instanciation de la classe patron

#include <cstdlib>#include <iostream>#include "Tableau.h"using namespace std;int main(int argc, char *argv[]){ Tableau<int,5> tab1; Tableau<double,7> tab2; int i; for(i = 0 ; i < 5 ; i++) { tab1.inserer(0,i); }//...

Page 357: Introduction à C++

Introduction à la programmation objet et générique avec C++ 357

Classes patrons (10)Classes patrons (10)✔ Paramètres non types des classes patrons (3/3)

– Dans l'exemple précédent on définit ainsi un tableau d'entier « int » de 5 cases et un tableau de réels « double » de 7 cases

• Tableau<int,5> tab1;• Tableau<double,7> tab2;

– Le type de ces paramètres doit être de l'un des types suivants• Type entier• Énumération• Pointeur sur membre• Pointeur• Référence

– La valeur de ces paramètres doit être constante.• Les pointeurs et les références doivent correspondre à des

objets ou des fonctions avec une édition de lien externe.

Page 358: Introduction à C++

Introduction à la programmation objet et générique avec C++ 358

Classes patrons (11)Classes patrons (11)✔ Paramètres non types des fonctions patrons (retour sur)

– Les paramètres non types sont utilisables également pour des fonctions patrons comme nous l'avions vu précédemment.

• Par exemple on pourrait avoir une fonction de tri qui prend en paramètre un Tableau<Type> et qui se définit à partir du type Type et d'un entier n, le tri s'effectuant jusqu'à la position indiquée par n.

Template <class Type, int n> void trier (Tableau<Type> &a){ //Trier jusqu'à la position n}//...Tableau<double> tableauDoubles;//...trier<double,8>(tableauDoubles);//...

Page 359: Introduction à C++

Introduction à la programmation objet et générique avec C++ 359

Classes patrons (12)Classes patrons (12)✔ Valeurs par défaut des paramètres de patrons de classes

– Les patrons de classes peuvent avoir des valeurs par défaut pour leurs paramètres

template <class Type = int, int n = 10> class Tableau{ private : Type elements[n]; public : Tableau(); ~Tableau(); bool inserer(const Type &element, int pos); Type getElement(int index); };

//... Tableau<> tab1; for(int i = 0 ; i < 10 ; i++) {tab1.inserer(0,i);}//...

Page 360: Introduction à C++

Introduction à la programmation objet et générique avec C++ 360

Classes patrons (13)Classes patrons (13)✔ Lieu de définition des patrons (1/2)

– La définition d'un patron se rapproche de la définition d'un type

• En effet elle ne donne pas lieu directement à la génération de code et à la réservation de la mémoire lors de la compilation.

• C'est seulement lorsque le patron est « instancié » qu'il y a réservation de la mémoire et génération du code.

– C'est pourquoi, de manière générale on définira les patrons dans les fichiers en-têtes .h

• Il suffit alors d'inclure ce fichier en-tête dans les fichiers sources contenant les instanciations du patron de classe.

Page 361: Introduction à C++

Introduction à la programmation objet et générique avec C++ 361

Classes patrons (14)Classes patrons (14)✔ Lieu de définition des patrons (2/2)

– Néanmoins l'approche précédente comporte au moins 2 inconvénients lorsque le code concerné devient complexe et volumineux

• Le code source étant placé dans le .h il devient accessible à tous les utilisateurs du patron

• La durée de compilation du projet peut se trouver fortement augmentée

– Quand ces inconvénients deviennent rédhibitoires, il est possible d'adopter une démarche différente

• Séparer la déclaration (dans le .h) de la définition des patrons (dans le .cpp).

• Ces définitions doivent alors être précédées du mot-clé export.

– Cette seconde stratégie n'est rentable que dans des projets relativement avancés et conséquents.

Page 362: Introduction à C++

Introduction à la programmation objet et générique avec C++ 362

Classes patrons (15)Classes patrons (15)✔ Classes patrons et héritages (1/2)

– L'héritage et les patrons de classes peuvent se combiner de différentes manières

• Une classe ordinaire dérivée d'une classe patron– class B : public A <int>

• B dérive de la classe patron A<int> • On a une seule classe nommée B

• Patron de classes dérivé d'une classe « normale »– template <class T> class B : public A

• On obtient une famille de classe B

Page 363: Introduction à C++

Introduction à la programmation objet et générique avec C++ 363

Classes patrons (16)Classes patrons (16)✔ Classes patrons et héritages (2/2)

– L'héritage et les patrons de classes peuvent se combiner de différentes manières

• Patron de classes dérivé d'un patron de classes– template <class T> class B : public A <T>

• On définit une nouvelle famille de classes dérivées et on obtient autant de classes dérivées possibles que de classes de base possibles

– template <class T, class U> class B : public A <T>

• On définit une nouvelle famille de classes dérivées.

• Chaque classe de base possible peut engendrer autant de familles de classes dérivées possibles de paramètre class U.

Page 364: Introduction à C++

Introduction à la programmation objet et générique avec C++ 364

Fonctions et classes patrons (1)Fonctions et classes patrons (1)✔ A retenir (1/2)

– Un patron de fonction est un « moule » qui permet au compilateur de fabriquer, en fonction des besoins toutes une collection de fonctions appliquant un même traitement à des données de types différents

• Quand on appele une fonction définie par un patron, il faut spécifier les types qu'elle est supposée traiter

– Un patron de classe est un « moule » qui permet au compilateur de fabriquer, en fonction des besoins, toute une collection de classes appliquant un même ensemble de traitement à des données de types différents.

• Pour instancier une classe définie par un patron, il faut spécifier les types qu'elle est supposée traiter.

• Toutes les fonctions membres d'une classe définie par un patron sont elles-mêmes définies par des patrons de fonctions

Page 365: Introduction à C++

Introduction à la programmation objet et générique avec C++ 365

Fonctions et classes patrons (2)Fonctions et classes patrons (2)✔ A retenir (2/2)

– Les patrons de fonctions ou de classes doivent être définis dans les fichiers .h dans la plupart des cas.

– Une fois un patron défini, il est facilement utilisable, même sans connaître la programmation générique et la manière de définir des templates.

Page 366: Introduction à C++

Introduction à la programmation objet et générique avec C++ 366

Gestion des exceptions en C++

Page 367: Introduction à C++

Introduction à la programmation objet et générique avec C++ 367

Plan général du coursPlan général du cours✔ Une vue d'ensemble du C++

– Historique– Objectifs de conception du C++– Présentation d'ensemble du C++– Références bibliographiques

• Livre• Web

– Les outils utilisés dans ce cours✔ Introduction aux concepts de la programmation orientée

objet– Conception et « Orienté Objet »– Les cartes CRC

✔ Introduction au C++– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 368: Introduction à C++

Introduction à la programmation objet et générique avec C++ 368

Introduction au C++ (4/4) : sommaireIntroduction au C++ (4/4) : sommaire✔ Introduction au C++

– Généralités sur le C++– La programmation orientée objet en C++– La programmation générique en C++– Gestion des exceptions

Page 369: Introduction à C++

Introduction à la programmation objet et générique avec C++ 369

Introduction (1)Introduction (1)✔ Motivation

– Quand vous implémentez une bibliothèque vous pouvez prévoir la détection d'un certains nombres d'erreurs à l'exécution mais ne pas vraiment savoir ce qu'il faut faire ensuite pour les gérer.

– Quand vous utilisez une bibliothèque vous pourriez savoir comment traiter certaines erreurs survenant à l'exécution mais sans nécessairement pouvoir les détecter

• La notion d'exception est offerte pour traiter ce genre de problème

✔ Notion d'exception– Une fonction qui rencontre un problème qu'elle ne peut traiter

déclenche (on dit parfois « lance » ou « lève ») une exception en espérant que son appelant (direct ou indirect) pourra gérer le problème.

– Une fonction qui désire gérer ce type de problème peut indiquer qu'elle est disposée à intercepter l'exception.

Page 370: Introduction à C++

Introduction à la programmation objet et générique avec C++ 370

Introduction (2)Introduction (2)✔ Exemple introductif#include <cstdlib>#include <iostream>#include "Tableau.h"using namespace std;int main(int argc, char *argv[]){ Tableau<double,15> tab1; int i; for(i = 0 ; i <= tab1.taille ; i++) { try { tab1.inserer(0.5,i); //déclenche une exception } catch (ArrayIndexOutOfBoundException& e) { cout << e.getMessage(); } } //...

Page 371: Introduction à C++

Introduction à la programmation objet et générique avec C++ 371

Bloc try ... catch (1)Bloc try ... catch (1)✔ Bloc try

– Un bloc try délimite un contexte dans lequel des exceptions peuvent être levées.

• Quand une exception apparaît dans un bloc try, l'exécution du programme saute immédiatement au bloc catch en charge du traitement de cette exception, si ce dernier existe.

//... for(i = 0 ; i <= tab1.taille ; i++) { try { tab1.inserer(0.5,i);//déclenche une exception } catch (ArrayIndexOutOfBoundException& e) { cout << e.getMessage(); } } //...

Page 372: Introduction à C++

Introduction à la programmation objet et générique avec C++ 372

Bloc try ... catch (2)Bloc try ... catch (2)✔ Bloc catch

– Un ou plusieurs blocs catch suivent un bloc try, afin de définir les traitements à apporter à des types précis d'exceptions levées dans le bloc try correspondant.

– Les blocs catch sont examinés dans l'ordre dans lequel ils apparaissent à la suite du bloc try

• Lorsqu'une exception est levée dans un bloc try, le premier des blocs qui correspond au type de l'exception ou type de l'une de ses superclasses est appelé.

– Donc pour traiter différemment les exceptions d'une classe dérivée et de sa classe de base, le bloc catchde la classe dérivée doit apparaître en premier.

– Attention• les exceptions sont souvent déclarés comme des

références dans les « paramètres » du bloc catch afin que le comportement polymorphique puisse avoir lieu.

Page 373: Introduction à C++

Introduction à la programmation objet et générique avec C++ 373

throw (1)throw (1)✔ Opérateur throw

– Pour lever une exception on utilise l'opérateur throw suivi de l'objet représentant l'exception que l'on veut lever

• Le type de l'exception permet de sélectionner le bloc catch à appeler.

• L'exception levée est passée comme paramètre du bloc catch pour qu'il puisse l'exploiter dans sont traitement.

– Il est notamment possible de lever une nouvelle fois l'exception au sein du bloc catch en appelant l'opérateur throw sans opérande.

– Dans un bloc try on peut lever directement une exception avec throw ou utiliser une fonction qui utilise elle-même throw et donc est susceptible de lever une exception.

Page 374: Introduction à C++

Introduction à la programmation objet et générique avec C++ 374

throw (2)throw (2)✔ Opérateur throw : exemple (1/2)

//... for(i = 0 ; i <= tab1.taille ; i++) { try { tab1.inserer(0.5,i);//déclenche une exception } catch (ArrayIndexOutOfBoundException& e) { cout << e.getMessage(); } } //...

Page 375: Introduction à C++

Introduction à la programmation objet et générique avec C++ 375

throw (3)throw (3)✔ Opérateur throw : exemple (2/2)

//...template <class Type, int n> void Tableau<Type,n>::inserer(const Type &element, int pos) throw (ArrayIndexOutOfBoundException){ if ( (pos >= 0) && (pos < n)) { elements[pos] = element; } else { ArrayIndexOutOfBoundException e(pos); throw e; } } //...

Page 376: Introduction à C++

Introduction à la programmation objet et générique avec C++ 376

Compléments sur les exceptionsCompléments sur les exceptions✔ Type des exceptions

– Les exceptions peuvent être de types intrinsèques (les types définis dans le langage) ou de types définis par l'utilisateur.

– Le type exception n'hérite pas obligatoirement d'une classe particulière (contrairement à Java par exemple)

✔ Exceptions standards– Certaines exceptions standard sont définies pour être utilisées

par le langage lui-même et la bibliothèque standard C++.– Les exceptions standard héritent toutes de la classe exception, définie dans le fichier d'en-tête standard <exception>

• La classe exception définie une fonction membre whatqui renvoie le nom de l'exception standard.

– On peut, mais ce n'est pas une obligation, faire hériter nos propres exceptions de la classe exception.

Page 377: Introduction à C++

Introduction à la programmation objet et générique avec C++ 377

Exemple d'exceptions définis par l'utilisateurExemple d'exceptions définis par l'utilisateur

#include <sstream>#include "ArrayIndexOutOfBoundException.h"ArrayIndexOutOfBoundException::ArrayIndexOutOfBoundException(int index){ this->index = index; stringstream sstr; sstr << endl << this->what() //...this->message = sstr.str(); }ArrayIndexOutOfBoundException::~ArrayIndexOutOfBoundException() throw(){}string ArrayIndexOutOfBoundException::getMessage(){ return message; }

#include <exception>#include <string>using namespace std;class ArrayIndexOutOfBoundException : public exception{ private : int index; string message; public : ArrayIndexOutOfBoundException(int index=-1); ~ArrayIndexOutOfBoundException()throw(); string getMessage(); };

Page 378: Introduction à C++

Introduction à la programmation objet et générique avec C++ 378

Compléments sur le bloc catchCompléments sur le bloc catch✔ Capture de tout type d'exception

– Une série de 3 point (« ... ») peut être utilisé comme paramètre du bloc catch pour définir que tout type d'exception doit être traité dans ce bloc.

• catch(...) { //...}✔ Non traitement des exceptions levées

– Si aucun bloc catch ne peut traiter l'exception levée, la pile d'appels est remontée à la recherche d'un bloc catch correspondant

• Si la pile d'appels est complétement vidée sans qu'un bloc catch satisfaisant n'ait été trouvé, la fonction standard terminate est appelé.

– Le comportement par défaut de la fonction standard terminate est d'arrêter l'exécution du programme.

Page 379: Introduction à C++

Introduction à la programmation objet et générique avec C++ 379

Spécifications d'exceptions (1)Spécifications d'exceptions (1)✔ Définition

– Spécifier des exceptions consiste à indiquer que la fonction que nous définissons peut lever certaines exceptions et si elle en lèvent ne lèvera que celles-ci.

✔ Intérêt– Spécifier des exceptions pour une fonction offre une garantie

au code appelant cette fonction que seules certaines exceptions peuvent être levées au sein de celle-ci

– Si une fonction lève une exception d'un des types non présent dans la spécification et non dérivé de l'un des types d'exception indiqués, la fonction standard unexpected est appelée.

• Le comportement par défaut de cette fonction est d'arrêter l'exécution du programme.

• Il est possible de modifier le comportement par défaut de la fonction standard unexpected.

Page 380: Introduction à C++

Introduction à la programmation objet et générique avec C++ 380

Spécifications d'exceptions (2)Spécifications d'exceptions (2)✔ Compléments sur la spécifications d'exceptions

– Un ensemble vide de parenthèses à la suite du throw indique qu'une fonction ne lève aucune exception

– Si l'on ne spécifie pas d'exceptions avec le mot-clé throw, il n'y a pas de limite sur le nombre ou le type des exceptions qui peuvent être levées.

– Les exceptions spécifiées dans la définition de la fonction doivent être les mêmes que les exceptions spécifiées pour sa déclaration.

– Si des exceptions sont spécifiées pour une fonction membre virtuelle, toutes les fonctions membres des classes dérivées qui redéfinissent cette fonction doivent spécifier les mêmes exceptions.

Page 381: Introduction à C++

Introduction à la programmation objet et générique avec C++ 381

Fonction terminateFonction terminate✔ Modification du comportement de terminate

– Il est possible de modifier le comportement de la fonction terminate avec votre propre gestionnaire de fin de traitement d'exceptions

• Il faut utiliser la fonction set_terminate(), après avoir importé le fichier en-tête standard <exception>.

• La fonction set_terminate() prend pour paramètre un pointeur sur une fonction de signature

– void gestionnaire_terminate();• set_terminate() renvoie le gestionnaire

précédemment actif.• Le gestionnaire que vous proposez doit prendre toutes les

mesures nécessaires pour traiter les exceptions non prises en charge jusqu'alors et terminer l'exécution du programme.

– Attention, c'est une thématique avancé, soyez sûr que vous sachez ce que vous faites.

Page 382: Introduction à C++

Introduction à la programmation objet et générique avec C++ 382

Fonction unexpectedFonction unexpected✔ Modification du comportement de unexpected

– Il est possible de modifier le comportement de la fonction unexpected avec votre propre gestionnaire

• Il faut utiliser la fonction set_unexpected(), après avoir importé le fichier en-tête standard <exception>.

• La fonction set_terminate() prend pour paramètre un pointeur sur une fonction de signature

– void gestionnaire_unexpected();• set_unexpected() renvoie le gestionnaire

précédemment actif.• Le gestionnaire que vous proposez doit prendre toutes les

mesures nécessaires pour traiter les exceptions non spécifiées et terminer l'exécution du programme.

– Votre gestionnaire peut également lever ses propres exceptions.

– Attention, c'est une thématique de C++ avancé, soyez sûr que vous sachez ce que vous faites.