• Aucun résultat trouvé

Introduction à la Programmation Orientée Objet

N/A
N/A
Protected

Academic year: 2022

Partager "Introduction à la Programmation Orientée Objet"

Copied!
132
0
0

Texte intégral

(1)

Polytech Marseille , Prog. o. o. 1

Introduction à la

Programmation Orientée Objet

Marc DANIEL Ecole Polytech Marseille,

Campus de Luminy, case 925, 13288 Marseille cedex 9 Marc.Daniel@univ-amu.fr

Avril 2021 1

Plan

Les concepts de la programmation orientée objet 4

– un peu d’histoire 5

– de la nécessité de langages adaptés 7

– vers les langages objets 11

– les principes généraux 13

– la notion de classe 16

– quelques langages 18

De C à C++ 19

Les concepts des langages de classes ; implémentation en C++ 55

– les classes et les objets 56

– les opérateurs 90

– l’héritage 104

La généricité et les modèles 164

(2)

Polytech Marseille , Prog. o. o. 3

Plan (suite)

Quelques compléments 197

– La norme C++ 198

– Les espaces de noms 199

– Amitié, Héritage et Généricité 205

Les composants prédéfinis 207

– Les flux d’E/S 210

– La classe String 216

– Les conteneurs 221

– Les itérateurs 230

– Les algorithmes 234

– Les traitements numériques 235

Au sujet de C++11 norme 2011 236

Conclusion sur C++ 251

Glossaire partiel 255

Bibliographie succincte 258

annexes 259

3

Polytech Marseille , Prog. o. o. 4

Les concepts de la

programmation orientée objet

4

(3)

Polytech Marseille , Prog. o. o. 5

Introduction / histoire

La préhistoire :

– les années 60 et les débuts de la programmation et des langages

Les années 70-80 : La programmation structurée – analyse descendante

Þ décomposition suivant les traitements

Þ les logiciels sont organisés autour des actions qui traitent les objets

– séparation traitement et données

– interdépendance des données à l’intérieur des traitements – difficile à maintenir

Þ Programme = Algorithmes + données

5

Introduction / histoire

La programmation et la conception orientée objet Ou un besoin de qualité

– depuis 1975

– essor dans les années 85 (C++, Eiffel) – la consécration à partir des années 90

« La conception objet repose sur une idée apparemment élémentaire. Les systèmes informatiques réalisent certaines

actions sur certains objets. Pour obtenir des systèmes souples et réutilisables, il faut mieux structurer le logiciel

autour des objets que des actions »

(4)

Polytech Marseille , Prog. o. o. 7

Objectifs principaux (Génie Logiciel) : – réutiliser ce qui a déjà été écrit

• directement (le code, les modèles)

• adaptation (l’héritage)

– augmenter la qualité

• rapidité de la conception

• facilité de maintenance

• ergonomie d’utilisation

• fonctionnement simple et efficace Intro. / langages adaptés

développement

utilisation

7

Polytech Marseille , Prog. o. o. 8

Le logiciel doit être :

• valide

• robuste

• Modifiable (extensible)

• réutilisable

• Portable

• ergonomique

• efficace

La maintenance doit être facile

• évolution du logiciel (an 2000, Euro, …. !!!), vos futurs stages !!

• correction d’erreurs

Þ Le logiciel doit nécessairement être modulaire

• et … les modules doivent être indépendants Intro. / langages adaptés

8

(5)

Polytech Marseille , Prog. o. o. 9

Dans une application, les coûts les plus importants proviennent :

• De la programmation

• De la maintenance

– Modification des spécifications par le client – Non respect des spécifications

– Tests mal ou pas réalisés – Bugs inévitables

– Adaptation à de nouveaux environnements – …

Pour la rapidité

• Étude de la complexité

• Loi de Moore (1965) Intro. / langages adaptés

9

Critères de modularité : – Décomposition modulaire

• la méthode permet de décomposer un problème en sous-problèmes dont les solutions peuvent être recherchées séparément

– Composabilité modulaire

• la méthode fournit des éléments (modules) qui peuvent être combinés pour traiter de nouveaux problèmes

– Compréhensibilité modulaire

• la méthode produit des modules compréhensibles isolément

– Continuité modulaire

• une petite modification de la spécification n’amène des modifications que sur un ou quelques modules. Il ne doit pas y avoir d’impact sur l’architecture du système

– Protection modulaire

Intro. / langages adaptés

(6)

Polytech Marseille , Prog. o. o. 11

Une « société » de modules respectant les critères de modularité

module : unité syntaxique du langage

un module doit communiquer avec peu de modules

les échanges entre modules doivent être le plus réduits possibles

les échanges entre les modules sont clairement explicités dans la définition des modules

toute information concernant un module est privée, sauf si elle est explicitement déclarée publique

(masquage de l’information)

Intro. / vers les objets

11

Polytech Marseille , Prog. o. o. 12

les modules que l’on appellera objets

parlent peu

leurs conversations tiennent en quelques mots

leurs échanges sont publics, codifiés, donc à haute voix

la plupart des informations et des traitements sont privés

Intro. / vers les objets

12

(7)

Polytech Marseille , Prog. o. o. 13

première vision des objets (modules)

décomposition en modules sur la base de leurs structures de données

un module est décrit comme une implémentation de types abstraits de données et des traitements associés

tout type est un module et vise versa – y compris les types prédéfinis (int, float, …)

– Une structure au sens du C est un module sans traitement : ce n’est pas la logique de l’orienté objet

chaque module a une interface qui définit comment il dialogue avec les autres

– Ce qui est public – Ce qui est privé

Intro. / principes généraux

13

Programmation orientée objet

On s’intéresse aux objets avant de s’intéresser aux traitements

– le programme de plus haut niveau sera étudié le plus tard possible

La p.o.o relève de la création d’objets et de l’exécution d’envois de messages entre les objets

Quels sont les objets ? (il faut définir les bons objets) Quels traitement doivent-ils subir ?

Quels liens ont les objets entre eux ?

Intro. / principes généraux

(8)

Polytech Marseille , Prog. o. o. 15

La classe : un moule

une classe correspond à

– une structure de données abstraites

• partie structurelle composée de champs (appelés attributs ou membres)

– des traitements à effectuer sur ces structures

(appelés méthodes ou fonctions membres) deux méthodes importantes : créateur et destructeur

• services disponibles sur la structure (partie opérationnelle)

• les propriétés de ces services

– une interface (clairement identifiée) qui définit

• partie publique (ce que voit le client)

• les services accessibles auxquels on peut faire appel

• les variables visibles de l’extérieur (en nombre très réduit)

La façon dont les traitements sont réalisés ne regardent pas le monde extérieur

on peut modifier les attributs et les méthodes sans modifier l’interface

Intro. / la notion de classe

15

Polytech Marseille , Prog. o. o. 16

Les classes sont reliées entre elles par des relations d’héritage

– on réutilise – on spécialise

• différentier les traitements

• préciser les attributs

Les objets sont définis à partir des classes par moulage – instanciation par moulage

– la classe sert de modèle, de moule

On ne communique avec l’objet qu’en invoquant une des méthodes de son interface

On a une encapsulation des données et des traitements qui permet l’abstraction des données

(voir glossaire)

Intro. / la notion de classe

16

(9)

Polytech Marseille , Prog. o. o. 17

Une classe très incomplète

class Triangle {

Point _p1, _p2, _p3 ; // données privées public :

...

float aire (…) ; float perimetre (...) ; } ;

• En dehors de la classe, on peut calculer l’aire, le périmètre, mais pas faire référence aux Points _p1, _p2 ou _p3. Si nécessaire : fournir ce qu’il faut dans l’interface (accesseur get_p1, modifieur set_p1).

Triangle Mon_triangle ; float area ;

……

area = Mon_triangle.aire(…) ;

• Une classe Triangle_rectangle pourrait hériter de la classe triangle Intro. / la notion de classe

17

Intro. / langages objets

Simula

• 1966, compilé

Smalltalk

• années 72-80, interprété --> adapté au prototypage, aussi un système d’exploitation

C++

• années 85, norme C++ (1998)

Eiffel

• 1989 (un modèle de langage O.O. resté au stade universitaire)

Java

• années 95, interprété --> adapté au prototypage

Ada 95, Lisp, CLOS (Common Lisp Object System)

C#

(10)

Polytech Marseille , Prog. o. o. 19

De C à C++

19

Polytech Marseille , Prog. o. o. 20

De C à C++

C++ est une amélioration « compatible » de C – qui permet

• l’abstraction de données, la programmation objet

• la généricité, la gestion des exceptions

• ...

– beaucoup plus rigoureux que C – fortement typé

– langage de référence normalisé

– peut être aussi rapide que C (pas de mécanisme sous-jacent complexe)

20

(11)

Polytech Marseille , Prog. o. o. 21

De C à C++

Les moins de C++

– la compatibilité avec C

• langage pouvant être totalement ésotérique

• présence de deux syntaxes

• utilisation des fonctions C

– Attention, certains points du C ANSI sont incompatibles avec C++

• moins permissif

• prototype des fonctions

• les constantes

• …

langage complexe qui demande un apprentissage progressif

21

De C à C++

Il n’est pas possible de décrire toutes les possibilités de C++

– long – fastidieux

– certaines techniques sont à éviter

Il faut utiliser la documentation

– le livre le langage C++ de B. Stroustrup contient un manuel de référence (gros !)

Il faut « explorer » le langage progressivement au fur et à mesure des besoins

Toutes les « nouveautés » de C++ ne sont pas forcément des

(12)

Polytech Marseille , Prog. o. o. 23

Un premier programme C++

using namespace std ;

compilation et exécution (sous Unix)

De C à C++

#include <iostream>

using namespace std ; int main (void) {

cout << "hello the world" << endl ; return 0 ;

}

libertad:~/essai_C> g++ hello.cxx -o hello libertad:~/essai_C> ./hello

hello the world libertad:~/essai_C>

Remarque sur la norme ….

23

Polytech Marseille , Prog. o. o. 24

De C à C++

De nombreux mots clés réservés en plus

bool catch class const_cast

delete dynamic_cast explicit false

friend inline mutable namespace

new operator private protected

public reinterpret_cast static_cast template

this throw true try

typeid typename using virtual

wchar_t

Des opérateurs plus explicites

and (&&) not (!) not_eq (!=) or (||)

……..

(vérifier que ceux-ci sont connus du compilateur)

24

(13)

Polytech Marseille , Prog. o. o. 25

De C à C++

Commentaires

x = y ; // commentaire qui va jusqu’a la fin de la ligne // c’est aussi un commentaire

/* cela marche aussi mais pas de melange SVP

*/

une seule syntaxe pour les commentaires !

De l’importance – des commentaires

• explicites, complets, nombreux

– des entêtes

• systématiques, homogènes, précis

25

De C à C++

transtypage

– il existe un transtypage explicite (à privilégier/ transtypage implicite)

en C en C++

int i = 1 ; int i = 1 ;

float x = 6.28 ; float x =6.28 ;

i = (int) x; i = int (x) ;

x = (float) i ; x = float (i) ;

le transtypage de C est parfois indispensable :

ptr1 = char *(ptr2) ; // incorrect car 2 termes ptr1 = (char *) ptr2 ;// correct

– le transtypage a un usage précis et limité (C++ fortement typé) :

(14)

Polytech Marseille , Prog. o. o. 27

De C à C++

Les constantes

– oubliez le C (préprocesseur (#define), portée des constantes)

const int i = 12 ;

– la portée de i est restreinte à l’unité de compilation contenant la définition

.

Si nécessaire définir i dans un .h et inclure le fichier (#include …)

– c’est une vraie constante

– Une constante peut être définie par une expression qui peut être évaluée à la compilation

const int nmax = 100 ; const int max = 2 * nmax + 1 ;

– suffixe f (ou F) (float) et u(U) unsigned

const double pi = 3.141596234134567;// les decimales ne sont pas bonnes const float pi_court = 3.141596f ; // les constantes reelles double sinon

27

Polytech Marseille , Prog. o. o. 28

Déclaration au plus près des identificateurs – déclaration en début de bloc (C)

– déclaration au plus près (attention ensuite au domaine de validité)

Prendre des règles de strictes

De C à C++

28

(15)

Polytech Marseille , Prog. o. o. 29

De C à C++

#include <iostream>

int main (void) { int n = 100 ;

float y ; y = 10 ; float x ; x = y ;

float z = y ; // attention tout de meme ! for (int i = 0 ; i < n ; i = i + 1)

{

int j = 10 ; n = n + i + j ;

// attention, j est maintenant inconnu } // interdit d'utiliser i ainsi

n = n + i + j ; return 1 ; }

libertad:~/essai_C> g++ portee.c -o portee portee.c: In function `int main()':

portee.c:17: warning: name lookup of `i' changed for new ANSI `for' scoping

portee.c:10: warning: using obsolete binding at `i' portee.c:17: `j' undeclared (first use this function) portee.c:17: (Each undeclared identifier is reported only

once : for each function it appears in.) libertad:~/essai_C>

29

Les entrées/sorties de base : plus simples qu’en C – <stdio.h> disponible !

– Des flux (flots) prédéfinis dans <iostream> en particulier cin, cout, cerr : on envoie ou on récupère des informations de ces flux

De C à C++ : E/S

#include <iostream>

using namespace std ; int main (void) {

int i = 12 ; float x, y ;

cout << "i=" << i << endl ; cin >> x >> y ;

cerr << "j'avais demande des reels" << endl ;

libertad:~/essai_C> g++ impression.c -o impression libertad:~/essai_C> ./impression

i=12

3 4 j'avais demande des reels

libertad:~/essai_C>

(16)

Polytech Marseille , Prog. o. o. 31

Les entrées/sorties de base : chaîne de caractères

De C à C++ : E/S

#include <iostream>

using namespace std ; int main(void) {

char *ptr = "c'est mieux qu'en C";

char nom [128] ; int i ;

i = 1 ;

cout << "donner le nom et i : " ; cin >> nom >> i ;

cout << "apres lecture" << nom << i <<endl ; cout << ptr << endl ;

return 0 ; }

libertad:~/essai_C> g++ impression2.c -o impression2 libertad:~/essai_C> ./impression2

donner le nom et i : POLYTECH 2 apres lecturePOLYTECH2 c'est mieux qu'en C libertad:~/essai_C>

31

Polytech Marseille , Prog. o. o. 32

Portée des identificateurs ; opérateur ::

Attention à la portée des identificateurs et à ce genre de manipulation

De C à C++

#include <iostream>

using namespace std ;

int i = 0 ; // c’est le i global int main (void)

{ int i = 1 ; // la variable locale masque le i global cout << i << endl ; // la variable locale est affichée --> 1 cout << ::i <<endl ; // ::i fait référence à la variable globale

// --> 0 { int i = 2 ; // masque les deux précédentes

cout << i <<endl ; // la variable locale est affichée --> 2 cout << ::i <<endl ; // ::i fait référence uniquement à la

// variable globale --> 0 }

i = 3 ; // modifie le premier i local, le second // n’ayant plus d’existence return 0 ;

}

32

(17)

Polytech Marseille , Prog. o. o. 33

Le type référence

– type dérivée de T : T & type référence vers T

Une valeur de type référence est une adresse

Trois différences avec les pointeurs 1) initialisation obligatoire

2) toute opération sur la référence agit sur l’objet référencé (pas sur l’adresse)

3) la valeur de la référence (adresse) ne peut pas être modifiée

Intérêt : mécanisme d’échange entre fonctions et ….

De C à C++ : les fonctions

int ii = 0 ;

int & rr = ii ; // rr fait donc référence à ii

rr = rr + 1 ; // agit sur ce qui est référencé par rr.

// Donc ii vaut maintenant 1

33

Le prototypage

C++ est fortement typé

– contrôle systématique entre arguments et paramètres (ou paramètres effectifs et paramètres formels)

• (en nombre, en type)

– prototypage des fonctions est « obligatoire »

Utiliser le plus possible des fichiers de prototypage (.h)

De C à C++ : les fonctions

// attention la fonction puissance doit retourner une valeur // avec une instruction return

float puissance (float x, int n);

void bidon (int m) ;

(18)

Polytech Marseille , Prog. o. o. 35

Paramètres par défaut

On peut omettre de fournir des arguments

– si des valeurs par défaut ont été définies pour les paramètres – ces paramètres sont les derniers

– on peut passer un argument s’il existe une valeur par défaut – ce gère au niveau du prototype de la fonction

De C à C++ : les fonctions

#include <iostream>

using namespace std ;

void bidon (int, float = 10.0, int = 10) ;

// ou bidon (int m, float a = 10.0, int j = 10) ; int main (void)

{

bidon (1, 1.0, 2) ; bidon (1, 1.0) ; bidon (1) ; return 0 ; }

void bidon(int m, float a, int j) {

cout << "je porte bien mon nom " << m << " " << a << " " << j ; }

35

Polytech Marseille , Prog. o. o. 36

Passage des arguments - mécanisme de correspondance

En C++, le programmeur a la maîtrise du mécanisme 1) passage par valeur

une copie de l’argument est passé à la fonction

• problème de la copie à l'exécution (savoir le faire et temps)

• ne modifie pas l’original De C à C++ : les fonctions

#include <iostream>

void inutile (int m) {

// définition directe pas de prototypage : place sur le transparent m=m+1 ;

}

int main (void) {

int j = 0 ;

inutile (j) ; // j vaut 0 après l’appel return 0 ;}

36

(19)

Polytech Marseille , Prog. o. o. 37

Passage des arguments - mécanisme de correspondance 2) passage par pointeur (C)

• l’adresse de l’argument est passée

• la fonction manipule des pointeurs De C à C++ : les fonctions

#include <iostream>

void bidon (int *m) {

*m = *m + 1 ; }

int main (void) {

int j = 0 ;

bidon (&j) ; // l ’adresse de j est passée. En retour j=1 return 0 ;

}

37

2) passage par référence (C++)

• les paramètres sont de type référence

• les arguments sont directement manipulés De C à C++ : les fonctions

#include <iostream>

void bidon (int & m)

{ // m est une référence

m = m + 1 ; // revient à manipuler l’argument associé }

int main (void) {

int j = 0 ;

bidon (j) ; // Manipulation de l’adresse masquée. En retour j=1 return 0 ;

}

(20)

Polytech Marseille , Prog. o. o. 39

Passage des arguments - mécanisme de correspondance Favoriser le passage par référence :

• plus lisible

• le mécanisme à privilégier

• ajout du mécanisme const : la variable ne peut pas être modifiée – équivalent passage par valeur sans recopie

– permet d’éviter les recopies lourdes De C à C++ : les fonctions

#include <iostream>

void bidon (int & m, const int & l) ; // prototypage int main (void)

{

int j = 0 ; int l = 2 ;

bidon (j, l) ; // En retour j=3 et l vaut évidemment 2 return 0 ;

}

void bidon (int & m, const int & l)

{ // m et l sont des références m = l + 1 ; // l est non modifiable }

39

Polytech Marseille , Prog. o. o. 40

Remarques sur l’utilisation de « const »

const peut aussi être utilisé pour des variables passées par valeur (indépendant du mécanisme de passage)

• signale au compilateur qu’il ne doit pas accepter de modifier des valeurs recopiées ou signalées comme non modifiables

• sécurité de programmation, aide à la correction de programme

• excellente habitude

Attention à « const type *ptr »

– Signifie ptr est un pointeur sur un objet type constant

– « type *const ptr » signifie que ptr est un pointeur constant vers un objet type !!!

De C à C++ : les fonctions

void bidon (int & m, const float & l, const int n) {

// m et l sont des références // on travaille sur une copie de n // il est interdit de modifier l et n }

40

(21)

Polytech Marseille , Prog. o. o. 41

Fonctions en ligne : inline « comme une fonction classique »

Le compilateur insère le code de la fonction

• quand il rencontre un appel à la fonction (A PRIORI)

• permet d’économiser le mécanisme de transfert d’appel De C à C++ : les fonctions

#include <iostream>

using namespace std ;

inline double valeur_abs (double x) {

return ((x)>0 ? x : -x) ; }

int main (void) {

const double x = 4.0 ; const double x1 = -4.0 ;

cout << "valeur absolue de " << x << "=" << valeur_abs (x) << endl ; cout << "valeur absolue de " << x1 << "=" << valeur_abs (x1) << endl;

return 0 ; }

libertad:~/essai_C> g++ -o inline1 inline1.cxx libertad:~/essai_C> ./inline1

valeur absolue de 4= 4 valeur absolue de -4= 4 libertad:~/essai_C>

41

Fonctions en ligne : inline

Proche des macro-définitions C (toujours disponibles)

• mieux intégrées dans le langage et typées : à privilégier De C à C++ : les fonctions

#include <iostream>

using namespace std ;

inline void somme_dif (const int a, const int b, int & som, int & dif) {

som = a + b ; dif = a - b ; }

int main (void) {

const int a = 2 ; const int b = 1 ; int u, v ;

somme_dif (a, b, u, v) ; cout << "a+b=" << u << endl ;

libertad:~/essai_C> g++ -o inline2 inline2.cxx libertad:~/essai_C> ./inline2

a+b=3 a-b=1

libertad:~/essai_C>

(22)

Polytech Marseille , Prog. o. o. 43

Fonctions en ligne : inline

des contraintes pour ces fonctions : le code de la fonction doit être disponible à la compilation

– dans le même fichier source (exemple précédent) – dans un fichier .h inclus dans le source

• problème du code dans un .h

– inclus dans le .h avec un include

De C à C++ : les fonctions

// fichier inline.h

inline void swap (int & a, int & b);

#include "inline.hxx"

// fichier inline.hxx void swap (int & a, int & b) {

int c ; c = a ; a = b ; b = c;

#include "inline.h" } int main()

{

int a = 1 ,b = 2 ; swap (a,b) ; return 0 ; }

Même problème pour la généricité

43

Polytech Marseille , Prog. o. o. 44

Type booléen

– le type bool prend deux valeurs « true » et « false » – les conditions sont des expressions de type bool – conversion implicite entre

• true <--> 1 false <--> 0 ne pas utiliser

Types struct, enum, (union)

enum jours {lundi,mardi,mercredi, …} ; struct ma_structure {…} ;

jours un_jour ; // les valeurs prises par un_jour ne sont // pas « int »

ma_structure str ; // aussi valide enum jours autre_jour ;

struct ma_structure autre_str ;

// conversion implicite donnant la position int i = mercredi ; // i vaut 2

De C à C++ : les types

44

(23)

Polytech Marseille , Prog. o. o. 45

Allocation

– new type_objet alloue un objet de type type_objet

– new type_objet[n] alloue un tableau de n objets de type type_objet

type-objet est quelconque

n est une expression arithmétique quelconque

– le résultat d’un new est de type type_objet *

– en cas de problème, il y a lancement d’une exception ...

Libération

– delete adresse libère l’objet alloué à l’adresse adresse – delete [] adresse libère un tableau alloué à l’adresse adresse – delete et delete [] ne sont pas interchangeables

Oubliez malloc, calloc, free !

N’oubliez pas que l’allocation dynamique a un coût ...

De C à C++ : allocation de mémoire

int *c ;

c = new int (10) ; int *c ;

c = new int [10] ;

int *c ;

c = new int [10] ; delete [] c ;

45

C++ et les tableaux

La déclaration d’un tableau utilise une expression constante

– float V[3] // tableau de 3 réels dans V[0], V[1], V[2]

– char * a[10] // tableau de 10 pointeurs de char (a[0], a[1], …, a[9] )

Tableaux à plusieurs dimensions (attention au nombre d’indices !) – int mat [3][5] ; tableau de 3 vecteurs entiers de 5 éléments

– // int mat[3,5] ; est incorrect

– utilisation : mat[i][j] i = 0, … 2, j = 0, …, 4

void f (int ind) {

int T[ind] ; // « incorrect » : ind n’est pas une expression constante // il faut dans ce cas allouer dynamiquement le tableau (voir aussi TD) // ou utiliser un composant prédéfini vector qui fait de même

}

(24)

Polytech Marseille , Prog. o. o. 47

Passage d’un tableau en paramètre

#include <iostream>

void f(int t[]) // evidemment t[10] convient ! {

...

}

int main () {

int x[10] = {1,2,3,4,5,6,7,8,9,10};

f(x) ; return 0 ; }

#include <iostream>

void f(int matrice[3][5]) {

...

}

int main () {

int mat[3][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} ; f(mat) ;

return 0 ; }

C++ et les tableaux C++ et les tableaux

47

Polytech Marseille , Prog. o. o. 48

Problème des deux (ou plus) dimensions

#include <iostream>

void f(int matrice[][]) // impossible

{ // le calcul de l’adresse de matrice[i][j] est impossible ...

}

#include <iostream>

void f(int matrice[][5])

{ // ici le calcul de l’adresse de matrice[i][j] est possible // cette solution est valide

...

}

C++ et les tableaux

48

(25)

Polytech Marseille , Prog. o. o. 49

Problème des deux (ou plus) dimensions – une autre solution correcte

#include <iostream>

using namespace std ; const int dim_j = 5 ;

void f(int matrice[][dim_j],const int & dim_i) {

int i, j ;

for (i = 0;i < dim_i ; i = i + 1) for (j = 0 ; j < dim_j ; j = j + 1)

cout << matrice[i][j] << endl ; }

int main () {

int mat[3][dim_j]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} ; int dim_i

= 3;

f(mat, dim_i) ; return 0 ; }

C++ et les tableaux

49

Problème des deux (ou plus) dimensions – la solution la plus générale

#include <iostream>

using namespace std ;

void f(int v[],const int & dim_i, const int & dim_j) {

int i, j ;

for (i = 0;i < dim_i ; i = i + 1) for (j = 0 ; j < dim_j ; j = j + 1)

cout << v[i*dim_j+j] << endl ; // vérifiez le calcul ! }

int main () {

int mat[3][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} ; int dim_i = 3, dim_j = 5 ;

f(&mat[0][0], dim_i, dim_j) ; return 0 ;

}

C++ et les tableaux

(26)

Polytech Marseille , Prog. o. o. 51

Mémoire allouée à l’éxécution – ne pas oublier de désallouer

à la fin de l’utilisation

Cas du tableau à plusieurs dimensions

– tableau de tableaux de taille connue à la compilation

#include <iostream>

main() {

int (*mat)[4]; // le type est int (*) [4] ; int i,j ;

i=3 ;

mat = new int[i][4];

// on utilise ensuite mat[i][j]

}

C++ et les tableaux dynamiques

int *c ;

c = new int [10] ; // int d[] ; est incorrect

delete [] c ;

// new int [4][i] non : 4 éléments d’un tableau de taille «variable»

// new int [i][j] non

new int [i][4][5] // oui avec un type int (*)[4][5]

// new int [4][i][5] // non // new int [4][5][i] // non

51

Polytech Marseille , Prog. o. o. 52

Cas du tableau à plusieurs dimensions (2 !) – tableau de tableaux de tailles connues à l'exécution

#include<iostream>

using namespace std ; int main()

{

int l, c ; // On prend un tableau de l lignes et c colonnes int ** mat ; // pointeur sur un pointeur

l = 3 ; c = 4 ;

// tableau des pointeurs vers les vecteurs de c éléments mat=new int*[l];

// allocation des l vecteurs de c éléments for (int i = 0 ; i < l ; i = i +1)

{

mat[i]=new int[c];

for (int j = 0 ; j < c ; j = j +1) mat[i][j]= i + j;

}

for (int i = 0 ; i < l ; i = i + 1) {

for (int j = 0 ; j < c ; j = j + 1) cout << mat[i][j] << "\t" ; cout << "\n" ;

} }

C++ et les tableaux dynamiques

52

(27)

Polytech Marseille , Prog. o. o. 53

Passage du tableau en paramètre

#include <iostream>

void f(int **m, const int & dim_i, const int & dim_j) { // int m[][] n'est pas acceptable

for (int i = 0 ; i < dim_i ; i = i + 1) for (int j = 0 ; j < dim_j ; j = j + 1)

{ } // on peut utiliser ici m[i][j]

}

int main() {

int l, c ; int ** mat ; l = 3 ; c = 4 ;

// tableau des pointeurs vers les vecteurs de c éléments mat=new int*[l];

// allocation des l vecteurs de c éléments for (int i = 0 ; i < l ; i = i +1)

{ mat[i]=new int[c];

for (int j = 0 ; j < c ; j = j +1) mat[i][j]= i + j;

}

f(mat, l, c) ; return 0 ;}

C++ et les tableaux dynamiques

Il faut ensuite évidemment détruire dans l’ordre inverse toutes les zones allouées

53

Surcharge des fonctions

– offrir plusieurs définitions d’une même fonction (attention aux ambiguïtés)

• les types et/ou le nombre des paramètres doivent être différents : signature

• dans ces conditions, la valeur de retour peut être différente

• le choix de la fonction est géré en fonction des arguments

int max(const int, const int) ; // max de 2 entiers int max (const int, const int, const int) ; // max de 3 entiers // le max du tableau nombre d’éléments : 2ème paramètre

int max(const int [], const int)

// double max(const int, const int) est illégal

// légal le type des paramètres est différent des précédents double max(const double, const double) ;

De C à C++ : surcharges

(28)

Polytech Marseille , Prog. o. o. 55

Les concepts des langages de classes ; implémentation en C++

55

Polytech Marseille , Prog. o. o. 56

Les classes : introduction

Une classe est une implémentation d’un type abstrait de données

Les classes possèdent :

– des données membres (les attributs) – des fonctions membres (les méthodes)

Le nom de la classe est le spécificateur de type

Les objets de type X sont des instances de la classe X

Au delà des principes généraux il faut un langage d’implémentation

– C++ est un langage difficile et complet

– des variations suivant les langages (en particulier avec Java)

56

(29)

Polytech Marseille , Prog. o. o. 57

Les classes : introduction

Masquage de l’information

Séparation :

– membres et fonctions membres accessibles de l’objet (partie publique)

– membres et fonctions membres propres de l’objet (partie privée)

L’implémentation d’un objet peut être modifiée sans affecter les applications qui manipulent l’objet

– données membres, fonctions membres Partie privée

Partie publique Vision de l’utilisateur de la classe Vision du concepteur

de la classe

57

Masquage de l’information

il s’effectue à 3 niveaux – public

– protected

– private (c’est le statut par défaut)

Les classes : introduction

public protected

Accessible aux héritiers Accessible à la classe

private

Accessible à tous

(30)

Polytech Marseille , Prog. o. o. 59

Les classes : introduction

Une classe est une unité de compilation

un fichier entête (Classe.h) qui définit la classe

(appelé interface)

un fichier source (Classe.cxx) qui contient l’implémentation des fonctions membres

l’implémentation des fonctions peut se faire dans l’entête. Les fonctions sont alors inline par défaut

(se justifie pour des fonctions très courtes)

Une fonction implémentée dans Classe.cxx

– doit être qualifiée par le nom de la classe par l’opérateur de résolution de portée ::

type Classe::fonction_membre(signature) { …}

59

Polytech Marseille , Prog. o. o. 60

Une première classe : une classe Point

deux attributs réels – abscisse x et ordonnée y

en première approche, il faut – initialiser un point avec deux réels – déplacer un point de dx, dy – afficher les coordonnées du point

Les classes : introduction

60

(31)

Polytech Marseille , Prog. o. o. 61

Interface de la classe Point (version 1) : Point1.h

Impossible de consulter ni de modifier les coordonnées

On peut prévoir des accesseurs (get_x, get_y) ou modifieurs (set_x, set_y)

Les classes : introduction

// interface de la classe Point class Point

{ private :

// on aurait pu choisir de déclarer x et y protected float _x, _y ;

public :

void initialiser (float, float) ; void deplacer (float, float) ; void afficher (void) ;

} ;

61

Implémentation de la classe Point (version 1) : Point1.cxx

Les classes : introduction

// implémentation des fonctions membres de la classe Point //

#include <iostream>

using namespace std ;

#include "Point1.h"

void Point::initialiser (float abscisse, float ordonnee) {

_x = abscisse ; _y = ordonnee ; }

void Point::deplacer(float dx, float dy) {

_x = _x + dx ; _y = _y + dy ; }

void Point::afficher(void) {

(32)

Polytech Marseille , Prog. o. o. 63

Appel de la classe point (version 1) : essai_Point1.cxx

Les classes : introduction

#include "point1.h"

using namespace std ; int main (void) {

// déclaration d'un objet point, instance de la classe point Point p ;

// remarquez comment s'appelle une fonction membre p.initialiser (1.0f, 2.0f) ;

p.afficher () ;

p.deplacer (0.1f, -0.1f) ; p.afficher () ;

return 1 ; }

libertad:~/essai_C> g++ -c Point1.cxx libertad:~/essai_C> g++ -c essai_Point1.cxx

libertad:~/essai_C> g++ -o essai_Point1 essai_Point1.o Point1.o libertad:~/essai_C> ./essai_Point1

les coordonnees du point sont : (1,2) les coordonnees du point sont : (1.1,1.9) libertad:~/essai_C>

63

Polytech Marseille , Prog. o. o. 64

Les classes : vie d’un objet

Un objet, instance d’une classe est : – créé

– initialisé – utilisé

• consulté

• modifié

– libéré – détruit

Les constructeurs et le destructeur sont des fonctions membres particulières A l’aide d’un des constructeurs

* ( par défaut )

* ou géré par le concepteur

Fonctions membres

A l’aide d’un destructeur géré par le concepteur

64

(33)

Polytech Marseille , Prog. o. o. 65

Les classes : vie d’un objet

Un constructeur est une fonction membre dont le nom est le même que celui de la classe

Un constructeur n’a pas de type

On peut avoir plusieurs constructeurs

En fonction du nombre et du type des arguments passés à l’appel, le bon constructeur est choisi

Dès qu’il existe un constructeur explicite, le constructeur par défaut de C++ n’est plus accessible

65

Les classes : vie d’un objet

Un premier exemple de constructeur (1/2)

// interface de la classe Point class Point

{

private : float _x, _y ; public :

Point (float, float) ;

void initialiser (float, float) ; void deplacer (float, float) ; void afficher (void) ;

Point fonction_membre (…) ; } ;

(34)

Polytech Marseille , Prog. o. o. 67

Les classes : vie d’un objet

Un premier exemple de constructeur (2/2)

On peut aussi utiliser le constructeur – attention à la recopie ...

// implémentation des fonctions membres de la classe Point //

#include "Point1.h"

#include <iostream>

Point::Point (float abscisse, float ordonnee) { _x = abscisse ;

_y = ordonnee ; }…

Point Point::fonction_membre (…)

{ …

return Point (a, b) ; // ce qui crée un nouveau point }

Point p1 (1.0f, 1.0f) ;

Point p2 = Point (1.0f, 2.0f) ;

67

Polytech Marseille , Prog. o. o. 68

Les classes : différents objets

Objets statiques

– variables globales ou objets déclarés static. Définis à la compilation

• durée de vie = durée de l’exécution du programme

Objets automatiques – variables locales.

• Appel constructeur : au moment de la définition de l’objet

• Appel destructeur : fin de portée de l’objet

Objets dynamiques

– définis par un pointeur sur une zone allouée par new

• durée de vie entre le new et le delete

68

(35)

Polytech Marseille , Prog. o. o. 69

Les classes : différents objets

Objets temporaires

– créés à l’exécution ( ex : return (Point (a, b) ) ; )

– création d’un objet temporaire sans nom

• Appel constructeur : au moment de la définition de l’objet

• Appel destructeur : fin de l’expression la plus englobante contenant l’objet

– créés par le compilateur (calculs intermédiaires)

• Nécessite la définition d’un constructeur par recopie

69

Les classes : this

Paramètre caché de toutes les fonctions membres : this

implicitement défini (auto-référencé)

this est un pointeur sur l’objet manipulé – this

– *this

Son usage est implicite ou explicite

Accessible à toutes les fonctions membres (non statiques)

(36)

Polytech Marseille , Prog. o. o. 71

Les classes : this

Exemples d’utilisation

L’utilisation de « this » est parfois réellement indispensable – ex : return *this ;

// implémentation des fonctions membres de la classe Point //

#include "Point1.h"

void Point::initialiser (float _x, float ordonnee) {

this->_x = _x ; // indispensable car _x paramètre cache // le membre _x !!

this ->_y = ordonnee ; // correct mais inutile }

void Point::deplacer (float dx, float dy) {

this->_x = this->_x + dx ; // pourquoi faire simple this->_y = this->_y + dy ; // c’est totalement inutile ici }

71

Polytech Marseille , Prog. o. o. 72

Les classes : constructeurs

Trois constructeurs (1/2)

Le constructeur par défaut – pas de constructeur proposé

• toujours un synthétisé par le compilateur (peut-être dangereux)

– un constructeur sans paramètre proposé

– un constructeur ayant tous ses paramètres par défaut

le constructeur par défaut doit pouvoir être appelé sans paramètre

– Il est appelé automatiquement dans certaines situations (ex. objets membres)

Le constructeur avec initialisation

– voir l’exemple de la classe Point

72

(37)

Polytech Marseille , Prog. o. o. 73

Les classes : constructeurs

Trois constructeurs (2/2)

Le constructeur par recopie (d’un autre objet) – le premier paramètre est une référence de l’objet à cloner

classe::classe (const classe & cloneur, .) ou classe::classe (classe & cloneur, …)

• & : pour la « recopie » éventuelle des zones dynamiques de l’objet

• Ne peut pas être passé par copie puisque c’est ce que l’on cherche à définir !

• s’il y a d’autres paramètres, ils doivent tous avoir des valeurs par défaut

• const obligatoire dans certains cas (objets sans nom retourné par recopie)

– Il est conseillé d’avoir un constructeur par recopie

• évite la synthétisation automatique erronée par le compilateur (cas complexes)

L’appel à un constructeur suit la création de l’objet – en particulier : il a sa place mémoire (sauf les parties dynamiques

éventuelles) 73

Les classes : constructeurs

Un cas particulier important (1/2)

Les membres de la classe sont des objets (objets membres) – Comment initialiser les objets membres ? (au moment de leur

création)

class Segment { Point a, b ; public :

Segment (float, float, float, float) ;

…};

…Segment::Segment (float x1, float y1, float x2, float y2) : a (x1, y1), b (x2, y2)

{ …} // ainsi les points a et b sont initialisés

(38)

Polytech Marseille , Prog. o. o. 75

Les classes : constructeurs

Un cas particulier important (2/2)

Cas de la constante membre (non déclarée static) – Comment initialiser la constante membre ?

class Complexe {

const bool reel ; float _a,_b ;

… public :

Complexe (float xx, float yy) : reel (false) {…}

Complexe (float xx) : reel (true) {…}

...

};

– reel est initialisée à la création et ne peut plus être modifiée

Même problème pour les membres de type reference

75

Polytech Marseille , Prog. o. o. 76

Les classes : destructeur

Le destructeur

le destructeur de la classe « Classe » est la fonction membre de nom :

~Classe (void)

Il n’a pas de type ni de paramètre

Il libère en particulier la mémoire allouée

L’appel au destructeur précède la destruction de l’objet

Une classe peut ne pas avoir de destructeur

– toujours un synthétisé par le compilateur (peut être dangereux)

76

(39)

Polytech Marseille , Prog. o. o. 77

Les classes : synthèse constructeurs et destructeur

Interface de la classe Point (version 2) : point2.h

// interface de la classe Point class Point

{ float _x, _y ; public :

// les constructeurs

Point (void) ; // constructeur par défaut Point (const float) ; // un deuxième constructeur Point (const float, const float) ; // encore une surcharge Point (const Point &) ; // constructeur par recopie

// ce constructeur pourrait // avoir d’autres paramètres

// avec des valeurs par défaut ! void initialiser (float, float) ;

void deplacer (float, float) ; void afficher (void) ;

// le destructeur

~Point (void) ; };

77

Les classes : synthèse constructeurs et destructeur

Implémentation de la classe Point (version 2) : Point2.cxx

// implémentation des fonctions membres de la classe Point

// #include <iostream>

#include "Point2.h"

using namespace std ; Point::Point(void) { _x = 0.0 ;

_y = 0.0 ;

cout << "constructeur par defaut" << endl ; } // ou Point::Point(void): _x(0),_y(0) {…}

Point::Point(const float r) {

_x=r ; _y=r ;

cout << "constructeur 1 parametre" << endl ; }

// ou Point::Point(const float r): _x(r),_y(r) {…}

...

Point::Point(const float r, const float t) {

_x = r ; _ y = t ;

cout << "constructeur 2 parametres" << endl ; }

// ou Point::Point(const float r, const float t) : _x(r),_y(t) { …}

Point::Point (const point & p) { _x = p._x ;

_y = p._y ;

cout << "constructeur par recopie" << endl ; }

Point::~Point (void)

{ cout << "destructeur" << endl ; }

(40)

Polytech Marseille , Prog. o. o. 79

Appel de la classe Point

(version 2) : essai_point2.cxx

Les classes : synthèse constructeurs et destructeur

#include "Point2.h"

Point a ;

//--- Point creepoint(void)

{

Point p = Point (7.0, 8.0) ; return (p) ;

}

//--- int main(void)

{

Point b(5.0), c(5.0, 2.0), e(b), f = c ; Point * d ;

a.afficher( ); b.afficher( ); c.afficher( );

d=new Point(6.0); d->afficher( ); delete d ; e.afficher( ); f.afficher( );

f =creepoint( ); f.afficher( );

return 1 ; }

libertad:~/essai_C> ./essai_point2 constructeur par defaut constructeur 1 parametre constructeur 2 parametres constructeur par recopie constructeur par recopie

les coordonnees du point sont : (0,0) les coordonnees du point sont : (5,5) les coordonnees du point sont : (5,2) constructeur 1 parametre les coordonnees du point sont : (6,6) destructeur

les coordonnees du point sont : (5,5) les coordonnees du point sont : (5,2) constructeur 2 parametres constructeur par recopie destructeur

destructeur

les coordonnees du point sont : (7,8) destructeur

destructeur destructeur destructeur destructeur libertad:~/essai_C>

?

?

79

Polytech Marseille , Prog. o. o. 80

Les classes : opérations par défaut On peut :

Instancier des objets et utiliser un constructeur :

class C

{ …} ; // déclaration de la classe C ...C objet1, objet2 ;

Pointer sur un objet Faire référence à un objet

C * p ; C & ref = objet2 ;

p = & objet1 ;

Affecter un objet

objet1= objet2 ;

– lors de l’affectation, il n’y a pas, par défaut, de recopie de la partie dynamique éventuelle. Il y a juste affectation du pointeur

– Si nécessaire, gestion explicite obligatoire par surcharge de l’opérateur d’affectation

80

(41)

Polytech Marseille , Prog. o. o. 81

Variable membre statique

Variable partagée par tous les objets de la classe – stockée à un seul endroit et initialisée

• hors de la classe et hors de toute fonction membre

Il existe aussi des constantes membres static Les classes : membres statiques

// interface de la classe Point class Point

{ float _x, _y ;

static int _nb_points ; // ou public public :

// les constructeurs

Point(void) ; // le destructeur...

~Point(void) ; };

// fonctions membres de la classe Point int Point::_nb_points = 0 ;

Point::Point(void) { _x = 0.0 ;

_y = 0.0 ;

_nb_points = _nb_points + 1 ; }

Point::~Point(void)

{_nb_points = _nb_points - 1 ; }...

81

Fonction membre constante : important

Fonction qui peut consulter l’objet mais pas le modifier

type Classe::nom_fonction (signature) const ;

Peut s’appliquer sur un objet const (autrement : illégal) Les classes : fonctions membres

// interface de la classe Complexe class Complexe

{ float _a, _b ; public :

...float get_a(void) const { return _a ; } float get_b(void) { return _b ; } };

#include "Complexe.h"

….

const Complexe c(1.0,1.0) ;

float x = c.get_a () ; // autorisé // float y = c.get_b () ; est illégal

(42)

Polytech Marseille , Prog. o. o. 83

Fonction membre statique

Fonction qui manipule des membres statiques et peut ainsi être déclarée static

– utilisable partout par la référence à la classe – pas d’accès à this

Les classes : fonctions membres

// interface de la classe Point class Point

{ float _x, _y ;

static int _nb_points ; public :

static void afficher_compteur(void) ; };

// fonctions membres de la classe Point

int Point::_nb_points = 0 ; void Point::afficher_compteur(void) {

cout << _nb_points << endl ; }

...

// peut ensuite être appelée // n’importe où

...

Point::afficher_compteur() ; ...

83

Polytech Marseille , Prog. o. o. 84

Les classes : des membres et fonctions membres !

On peut aussi avoir :

des membres mutable

– modifiable même s’il appartient à un objet const

• (ex : nb_consultations d’un objet)

des pointeurs sur des membres

des pointeurs sur des fonctions membres – l’identificateur d’une fonction est un pointeur – la valeur du pointeur peut changer

• même syntaxe pour différents appels !

« lire la doc ! »

84

(43)

Polytech Marseille , Prog. o. o. 85

Les classes : tableaux d’objets

On peut créer des tableaux d’objets – à 1, 2 ou n indices

– conformes aux tableaux vus dans la partie précédente – statiques, automatiques ou dynamiques

Une bonne règle : l’objet doit avoir un constructeur par défaut

On peut créer des opérations de « haut niveau » !

class Complexe {

…public

Complexe(float = 0.0, float = 0.0) ; // constructeur par défaut

}; ….

Complexe ztab[100] ; ...

85

Les classes : l’amitié en C++

Une entorse aux concepts de P rogrammation O rientée O bjets

la partie private est réservée aux instances de la classe.

Les amis ou friend permettent de casser le mécanisme d’encapsulation et d’accéder aux informations de la classe

Les friend peuvent être : – des fonctions indépendantes

– des fonctions membres d’une autre classe – des fonctions amies de plusieurs classes – des classes amies

L’abus des « friend » est dangereux. A consommer avec

(44)

Polytech Marseille , Prog. o. o. 87

Les classes : l’amitié en C++

Un exemple pour « améliorer la performance »

class Tableau {

int *tab, taille ;

// définie ici ou en partie public friend void print(const Tableau &) ;

public :

Tableau(int n = 10) { taille = n ; tab = new int [taille] ; } // lancement d’une exception si problème d’accès

int & element(int i) { assert ( i < taille) ; return tab[i] ; } } ; …

void print(const Tableau & t)

{// « plus rapide » que de passer par la fonction membre element for (int i = 0 ; i < t.taille ; i = i + 1)

cout << t.tab [i] ; }

87

Polytech Marseille , Prog. o. o. 88

Un exemple de classe amie : une liste de chainons

class Chainon {

char *donnee ; // ou char donnee ; Chainon * suivant ;

friend class Liste ; } ;

class Liste

{ Chainon * tete ; public :

Liste (void) {

tete = new Chainon ; tete->suivant = NULL ; // accès au membre privé de tete } ; }

Remarque : exemple incomplet pour être opérationnel Les classes : l’amitié en C++

88

(45)

Polytech Marseille , Prog. o. o. 89

Les classes : l’amitié en C++

Attention : Les amis de mes amis ne sont pas mes amis

class A {

static const int _n = 100 ; friend class B ;

} ;

// la définition de la classe B est correcte class B

{ float tab[A::_n] ; friend class C ; } ;

// la définition de la classe C est incorrecte // il faudrait que C soit amie de A

class C {

int t [A::_n] ; } ;

89

Les opérateurs

Idée : étendre les opérateurs de base pour qu’ils puissent s’appliquer aux objets

– (ex : pour 2 complexes z1 et z2 z1 = = z2 z1 + z 2 )

Il existe des opérateurs – unaires &, new – binaires = =, <, <<, >>

– unaires et binaires +, -, * (pointeur), * (multiplication)

Les opérateurs ont un ordre de précédence (priorité) – z = a * b + c ; veut dire a * b

puis (a * b) + c

(46)

Polytech Marseille , Prog. o. o. 91

Les opérateurs

Les opérateurs unaires sont associatifs à droite

*p++ ; veut dire *(p++) ; (sans commentaire !)

= est associatif à droite : a = b = c veut dire a = (b = c)

Les opérateurs binaires sont associatifs à gauche a + b + c ; veut dire (a + b) + c ;

« lire la doc ! » pour – liste des opérateurs – les ordres de précédence

La programmation explicite des précédences et associativités est la règle pour les cas non triviaux

91

Polytech Marseille , Prog. o. o. 92

Les opérateurs

Les opérateurs prédéfinis peuvent être redéfinis pour les types de l’utilisateur donc pour les objets

Les opérateurs sont des fonctions

x = y + z ; veut dire operator= (x, operator+ (y, z) ) ;

Surcharger un opérateur : créer une nouvelle fonction – les règles des fonctions sont conservées

– les précédences, arités et associativités ne peuvent être modifiées – ne conserve pas nécessairement l’éventuelle commutativité

Il est impossible de créer de nouveaux opérateurs

Les opérateurs d’affectation (=) et d’adressage (&) sont implicitement définis, mais peuvent être redéfinis

– attention à l’implicite, ex : objet avec partie dynamique

92

(47)

Polytech Marseille , Prog. o. o. 93

Les opérateurs

Les opérateurs ne peuvent pas être surchargés pour les types prédéfinis (int, …)

Pas de surcharge possible pour

– . Sélection de membre ( objet.membre ) – .* ( objet.pointeur_de_membre )

– :: résolution de portée ( Classe::nom ) , global ( ::nom ) – ? : expression conditionnelle ( x>0 ? x : -x )

– sizeof taille de l’objet ( sizeof expr ), d’un type (sizeof (type) ) – #, ## gérés par le préprocesseur

93

Deux implémentations possibles, mais différentes (1/2)

redéfinir l’opérateur par une fonction membre

– implicitement, l’opérateur redéfini a un paramètre de plus (this) – pas de symétrie naturelle -> pas commutatif

– si le membre gauche est d’une autre classe : impossible – non static (sauf éventuellement new, new [], delete, delete [])

class Complexe { float _a, _b ; public :

Complexe(float = 0.0, float = 0.0) ; Complexe operator+(const Complexe &) ; } ; …

Complexe Complexe::operator+(const Complexe &z) { return Complexe (_a + z._a, _b +z._b) ; }

Les opérateurs

…Complexe z1, z2, z3 ; float x ;

// possible z3 = z1 + z2 ;

// possible avec conversion // implicite de type // x-> complexe (avec un // constructeur 1

paramètre) z3 = z1 + x ;

(48)

Polytech Marseille , Prog. o. o. 95

Les opérateurs

…Complexe z1 ; Complexe z2 ; Complexe z3 ; float x ; // possible z3 = z1 + z2 ; // possible avec // la conversion // implicite de x z3 = x + z1 ; z3 = z1 + x ;

Deux implémentations possibles, mais différentes (2/2)

redéfinir l’opérateur par une fonction non membre

– la fonction « doit être » amie pour accéder simplement aux membres – symétrie naturelle

– plus d’accès à this

class Complexe { float _a, _b ; public :

Complexe(float = 0.0, float = 0.0) ; friend Complexe operator+(const Complexe &,

const Complexe &) ;

… } ;

Complexe operator+(const Complexe & z1, const Complexe & z2)

{ return Complexe(z1._a + z2._a, z1. _b +z2._b) ; }

95

Polytech Marseille , Prog. o. o. 96

Les opérateurs

Point & operator = (const Point & p) {

_x = p._x ; _y = p._y ;

return *this ; // pourquoi * this ? }

opérateur d’affectation

Le type de retour d’une expression d’affectation est le type de l’opérande gauche avec une référence pour éviter la copie

L’opérande gauche « doit » être une lvalue modifiable – Pour pouvoir affecter !

Ne pas confondre

a = b ; et Point a = b ;

Attention, par défaut un opérateur d’affectation est synthétisé

– Copie membre à membre ….. y compris les pointeurs sur les parties dynamiques On pourrait écrire :

void operator= (…)

mais a=b=c soit : a=(b=c) serait impossible

Point operator = (…)

mais a=b=c impliquerait la copie de b

96

(49)

Polytech Marseille , Prog. o. o. 97

lvalue et fonction de type référence

A l’origine (d’autant que C++11 modifie les choses)

« Une lvalue est quelque chose qui peut être du côté gauche d’une affectation » (par opposition à une rvalue)

Plus précisément

« Un objet est une région de mémoire ; une lvalue est une expression qui fait référence à une zone mémoire », qui a donc une persistence dans le temps. On ne peut pas tout faire avec des rvalues !

Une lvalue peut être modifiable ou non (par exemple si elle est déclarée constante)

Certains opérateurs produisent des lvalues

Une fonction de type référence est une fonction retournant une lvalue, quelque chose qui « reste »

– Et qui évite une recopie

Les opérateurs

int & f(….) {...} // f retourne une lvalue de type int i=3 ;

lvalue= rvalue ;

97

opérateur d’indexation

Permet d’accéder directement aux éléments d’un tableau à l’extérieur de la classe

Les opérateurs

#include <iostream>

using namespace std ; class Vecteur { private :

int _T[10];

public :

Vecteur(){ …}

int & operator[](const int & i) { return _T[i] ;}

};

int main () {

Vecteur t ; int i = 1;

//cout << t._T[1] ; // accès à un variable privée; OK si en public cout << t[i] <<endl;

Références

Documents relatifs

L’interpréteur java permet d’exécuter une application écrite en langage java (autre qu’une applet), plus spécifiquement un fichier ClassName.class (i.e le java bytecodes). Par

Une interface est introduite par le mot clé « interface », et se comporte comme une classe dont toutes les méthodes sont abstract et dont tous les attributs sont final. Les mots

Additionner deux vecteurs donnés ; on écrira pour cela une méthode statique nommée aussi addition (en utilisant ainsi la possibilité de la surcharge) qui recevra en

Dans le cas de l’approche procédurale, un programme correspond à l’assemblage de plusieurs fonctions qui s’appellent entre elles. Exemple de langages de

Les exemples de code sont écrits en C#, mais sont facilement transposables à d'autres langages orientés objets comme

Les classes dérivées peuvent définir les propres membres, mais aussi redéfinir les méthodes de la classe mère. class particule

une commande est créée pour un client et un catalogue donnés, on peut ajouter des articles à une commande, accéder à la liste des articles commandés ainsi que prix total des

Cette méthode retourne vrai s’il existe une l’intersection ainsi que le point d’intersection faux, dans le cas contraire..  Une classe Droite constituée d’un Point et