• Aucun résultat trouvé

Chapitre 1. Introduction à la POO: Les classes vs les objets. 420-KAB-LG Programmation orientée par objets Hiver 2013

N/A
N/A
Protected

Academic year: 2022

Partager "Chapitre 1. Introduction à la POO: Les classes vs les objets. 420-KAB-LG Programmation orientée par objets Hiver 2013"

Copied!
239
0
0

Texte intégral

(1)

Chapitre 1

Introduction à la POO:

– Les classes vs les objets

420-KAB-LG Programmation orientée par objets 1

(2)

Programmation procédurale ou orientée par objets?

 La programmation procédurale:

 La programmation orientée par objets:

Tas de données

Méthode 1 Méthode 2 Méthode 3

Méthode 4 Méthode 5 Méthode 6

Données Données Données

Méthode 1 Méthode 2

Méthode 3 Méthode 4

Méthode 5 Méthode 6

(3)

Avantages de la POO

Pour le programmeur:

– Permet de rassembler des données qui vont

logiquement ensemble afin de les traiter comme un tout.

– Protège les données en limitant le traitement à ce qui est prévu par l’objet uniquement.

De façon plus générale:

– Elle augmente l’intelligibilité des programmes en rassemblant les données et les traitements qui

s’appliquent à elles.

– Elle facilite la réutilisation de morceaux de programmes.

– Elle facilite la mise à jour et l’ajout de

fonctionnalités.

420-KAB-LG Programmation orientée par objets 3

(4)

Un objet...

Définition: « Chose solide ayant unité et indépendance. »

 Dans le contexte informatique un objet peut représenter:

– Un objet concret : une chaise, un robot, une personne...

– Un objet abstrait: un compte de banque, un cours de programmation…

 Un objet se compare à une variable: il doit être

déclaré avant d’être utilisé et a une durée de vie.

(5)

Définition: « Idée abstraite servant à modéliser un ensemble d’objets concrets. »

 Une classe se compare à un type. L’existence d’un type ne représente rien tant qu’on n’a pas déclaré une variable.

La classe n’est qu’un moule servant à créer des objets.

 Un objet est aussi nommé une instance d’une classe.

 Une classe possède des membres:

Attributs: variables qui représentent les données de l’objet. Les valeurs de ces données sont les états de l’objet. Chaque objet a un ensemble d’attributs (de variables) qui lui est propre.

Méthodes: actions qui s’appliquent à l’objet ou encore services que peut rendre l’objet.

 On déclare des objets d’une classe tout comme on déclare des variables d’un certain type.

 La classe est une extension de la notion de structure...

420-KAB-LG Programmation orientée par objets 5

(6)

Attributs ou propriétés

Définition: « Une caractéristique ou un

état que possède tous les objets d’une

même classe mais dont le contenu peut

varier d’un objet à l’autre. »

(7)

Méthodes

Définition: « Une méthode est un sous- programme qui appartient à une classe et effectue un traitement sur les attributs de cette classe ».

 Une méthode peut servir à:

– Modifier la valeur d’un attribut (mutateur) – Obtenir la valeur d’un attribut (accesseur) – Effectuer un traitement plus général

420-KAB-LG Programmation orientée par objets 7

(8)

Les modificateurs d’accès

 public:

– Le membre est visible à l’intérieur de la classe comme de l’extérieur (interface).

 private:

– Le membre n’est visible qu’à l’intérieur de la classe (encapsulation).

 La seule différence entre une classe et une

structure est l’accès par défaut (si non spécifié):

– Pour une classe: private

– Pour une structure: public (rétrocompatibilité)

 protected:

– Le membre n’est visible qu’à l’intérieur de la classe et

ses dérivées (dans le contexte de l’héritage)

(9)

Représentation UML d’une classe

420-KAB-LG Programmation orientée par objets 9

Accès:

- Privé

+ Publique

# Protégé

Méthodes

Attributs

Nom

(10)

 Une classe a des méthodes et des attributs

(on peut faire la distinction entre un attribut fixe (caractéristique) ou variable (état))

 La classe se protège et assure sa cohérence interne!

 La classe fournie une interface simple (des méthodes publiques) mais complète!

Un attribut est toujours privé!

 Accès à un attribut:

Aucun

Lecture seule (accesseur)

Lecture et écriture (mutateur et accesseur)

(11)

Trois grands

principes de la POO

420-KAB-LG Programmation orientée par objets 11

(12)

1. L’encapsulation

Définition: « Exposer les fonctionnalités d’un objet tout en cachant les structures de données et les détails d’implémentation. »

 Indépendance:

– Afin d’assurer la cohérence interne d’un objet, seul ce dernier doit pouvoir lire et modifier ses attributs. Les attributs devraient donc toujours être privés!

– Les méthodes publiques implémentent l’interface d’utilisation. Elle doit être simple mais complète.

Elle doit aussi assurer la cohérence.

 Unité:

– Il existe un lien cohérent entre les attributs.

– Les méthodes doivent lire et/ou modifier les attributs.

(13)

2. L’héritage

 Permet la généralisation: c’est une caractéristique importante d’un langage naturel!

 Simplifie les programmes en évitant la redondance.

420-KAB-LG Programmation orientée par objets 13

(14)

3. Le polymorphisme

Définition: « Le polymorphisme consiste à faire abstraction de la forme. »

Prendre

l’automobile Prendre

l’autobus Méthode

abstraite

(15)

Un exemple en C++

class CBicyclette { public:

void Freiner();

void Pedaler();

string ObtenirCouleur() const;

void ModifierCouleur(string couleur);

private:

string Couleur_;

float Vitesse_;

int Hauteur_;

};

420-KAB-LG Programmation orientée par objets 15

(16)

Écriture d’une classe

Déclaration dans le .h:

class CEntierEncapsule {

int Entier_;

public:

void SetEntier(int NouvelEntier);

int GetEntier() const;

};

Définition dans le .cpp:

void CEntierEncapsule::SetEntier(int NouvelEntier) {

Entier_ = NouvelEntier;

}

int CEntierEncapsule::GetEntier() const {

return Entier_;

}

Utilisation:

int main() {

CEntierEncapsule UnObjet;

UnObjet.SetEntier( 10 );

cout << UnObjet.GetEntier();

}

(17)

Procédurale VS Objets

class CPersonne {

public:

int Age;

bool EstAdulte() {

return Age >=18;

} };

int main() {

CPersonne Joan;

Joan.Age = 19;

cout << Joan.EstAdulte();

}

420-KAB-LG Programmation orientée par objets 17

bool EstAdulte(int Param) {

return Param>= 18;

}

int main() {

int Age;

Age= 19;

cout << EstAdulte(Age);

}

(18)

Les méthodes constantes

 Le mot-clé const après la déclaration

d’une méthode garantit que cette méthode ne modifiera aucun des attributs de la

classe.

 C’est une protection pour le programmeur.

 C’est une excellente pratique que de déclarer les accesseurs const (ainsi que toute autre méthode qui n’a pas besoin de modifier les attributs de l’objet).

Exemple: int GetEntier() const;

(19)

Vers la POO: Avant

float Quotient(int Num, int Den) { float q =0.0f;

if(Den!=0)

q = (float)Num / (float)Den;

return q;

}

int main() { int n=3;

int d=4;

cout << Quotient(3,4) << endl;

}

420-KAB-LG Programmation orientée par objets 19

Ancienne façon de faire un cast

(20)

Vers la POO: Naissance

struct Fraction { int Num;

int Den;

}; float Quotient(Fraction Fr) { float q = 0.0f;

if(Fr.Den!=0)

q = static_cast<float>(Fr.Num) / static_cast<float>(Fr.Den) ; return q;

} int main()

{ Fraction Frac;

Frac.Num = 3;

Frac.Den = 4;

cout << Quotient(Frac) << endl;

Apparition d’un nouveau concept et

regroupement des données

(21)

Vers la POO: Intégration

class Fraction { public:

int Num;

int Den;

float Quotient()

{

float q = 0.0f;

if(Den!=0)

q = static_cast<float>(Num) / static_cast<float>(Den);

return q;

};

}

int main()

{ Fraction Frac;

Frac.Num = 3;

Frac.Den = 4;

cout << Frac.Quotient() << endl;

}

420-KAB-LG Programmation orientée par objets 21

Ajout de la méthode à la classe:

Regroupement des données et des

méthodes qui utilisent ces données

(22)

Ce qu’il faut retenir...

 Il faut bien comprendre les structures (ref.

KA0) pour apprendre la POO.

 À partir de maintenant nous ajouterons des fonctions à nos structures!

 Nous utiliserons le mot-clé class au lieu de

struct mais il y a peu de différences pour le

compilateur

(23)

Chapitre 2

Le cycle de vie

420-KAB-LG Programmation orientée par objets 23

Construction Utilisation Destruction

(24)

Les services par défaut d’une classe

1. La construction

– Allocation de la mémoire – Attributs non-initialisés

2. La construction d’une copie

– Allocation de la mémoire

– Copie membre à membre (shallow copy)

3. L’affectation entre objets d’une même classe

– Copie membre à membre (shallow copy)

4. La destruction

– Libération de la mémoire

 Les services par défaut peuvent être redéfinis!

(25)

Exemple

// Fichier EntierEncapsule.h class CEntierEncapsule

{

public:

int GetEntier() const;

void SetEntier(int Entier);

private:

int Entier_;

};

420-KAB-LG Programmation orientée par objets 25

(26)

Exemple (suite)

int main() {

CEntierEncapsule Entier1, // Construction par défaut Entier2;

Entier1.SetEntier(10);

AfficherObjet(Entier1);

Entier2 = Entier1; // Affectation d’un objet à un autre AfficherObjet(Entier2);

} // Destruction des objets

void AfficherObjet(CEntierEncapsule Param)

// Construction d’une copie {

cout << Param.GetEntier() << endl;

} // Destruction de l’objet

// passé en paramètre

(27)

Les services par défaut (suite)

 Parfois le service par défaut ne suffit pas!

– Par exemple, la construction par défaut n’initialise pas les attributs!

 Nous pouvons implémenter nous-même la construction d’un objet, la copie,

l’affectation et la destruction d’un objet.

420-KAB-LG Programmation orientée par objets 27

(28)

Les services par défaut (suite)

 La déclaration d’un constructeur permet

d’initialiser l’objet après l’allocation de l’objet.

 La déclaration d’un constructeur de copie dans une classe remplace le constructeur de copie par défaut.

 La déclaration d’un destructeur dans une classe permet de faire le ménage avant la libération de l’objet.

 La surcharge de l’opérateur = remplace le

service par défaut d’affectation.

(29)

Le constructeur

 Qu’affiche à l’écran le programme suivant?

int main() {

CEntierEncapsule UnObjet;

cout << UnObjet.GetEntier() << endl;

}

 Une valeur aléatoire car la construction par défaut n’initialise pas les attributs! (comme au laboratoire!)

420-KAB-LG Programmation orientée par objets 29

(30)

Le constructeur (suite)

Il faudrait plutôt faire:

int main() {

CEntierEncapsule UnObjet;

UnObjet.SetEntier(20);

cout << UnObjet.GetEntier() << endl;

}

 Cela ne devrait pas être la responsabilité de

l’utilisateur de la classe d’initialiser l’objet, mais

à l’objet lui-même de s’initialiser correctement!

(31)

Le constructeur (suite)

 Lors de la construction d’un objet, le compilateur

invoque automatiquement une méthode qui se charge de l’initialisation de l’objet. Cette méthode spéciale se

nomme un constructeur.

 Il doit initialiser tous les attributs et exécuter toutes autres instructions requises pour initialiser l’objet.

 N’a pas de valeur de retour (même pas void!)

 Porte le même nom que la classe.

 Peut avoir des paramètres ou non.

 On peut définir plusieurs constructeurs pour une même classe, mais ils doivent avoir des signatures différentes.

420-KAB-LG Programmation orientée par objets 31

(32)

Le constructeur sans paramètres

 Il est unique!

class CEntierEncapsule {

public:

CEntierEncapsule(); // Même nom que la classe // pas de type de retour!

};

CEntierEncapsule::CEntierEncapsule() // Définition {

Entier_ = 0; // ou encore mieux SetEntier(0);

}

(33)

Le constructeur sans paramètre (suite)

Et maintenant, qu’affiche à l’écran le programme suivant?

int main() {

CEntierEncapsule UnObjet;

cout << UnObjet.GetEntier() << endl;

}

Il affiche 0 ! N’est-ce pas génial??

420-KAB-LG Programmation orientée par objets 33

(34)

Les constructeurs avec paramètre(s)

class CEntierEncapsule {

public:

CEntierEncapsule(int Valeur); // Même nom que la classe // pas de type de retour!

}; // un paramètre int

CEntierEncapsule::CEntierEncapsule(int Valeur) {

Entier_ = Valeur; //ou encore mieux SetEntier(Valeur);

}

(35)

paramètres (suite)

int main() {

CEntierEncapsule UnObjet(99);

cout << UnObjet.GetEntier() <<

endl;

}

Il affiche 99 !

420-KAB-LG Programmation orientée par objets 35

(36)

La valeur par défaut d’un paramètre

 En C++, un paramètre peut avoir une valeur par défaut.

 La valeur est définie dans le prototype seulement (.h).

 Si le paramètre n’est pas spécifié lors de l’appel, la valeur par défaut est utilisée.

Exemple:

void Afficher(string Message="Bonjour", int Fois = 1);

Peut être appelé de trois façons:

Afficher("Salut", 5); // Affiche Salut 5 fois Afficher("Allo"); // Affiche Allo 1 fois

Afficher(); // Affiche Bonjour 1 fois

Par contre, Afficher(5) donne une erreur de compilation…

(37)

constructeurs

 On peut donc remplacer plusieurs constructeurs par un seul constructeur avec des paramètres avec des valeurs par défaut!

 Évite la redondance du code.

class CPersonne {

public:

CPersonne(string Nom="Roger", int Age=20);

// remplace avantageusement:

// CPersonne();

// CPersonne(string Nom);

// CPersonne(string Nom, int Age);

};

420-KAB-LG Programmation orientée par objets 37

(38)

Le constructeur de copie

 Appelé de façon implicite lorsque:

1. Un objet est passé en tant que paramètre par valeur

2. Un objet est retourné par une fonction

3. Un objet est construit à partir d’un autre objet

 Son rôle est de créer une copie exacte de l’objet passé en paramètre

 Sa signature est toujours la même:

– NomClasse (const NomClasse& Original);

(39)

Le constructeur de copie

class CEntierEncapsule {

public:

CEntierEncapsule(const

CEntierEncapsule& Original);

};

CEntierEncapsule::CEntierEncapsule(const CEntierEncapsule& Original)

{

Entier_ = Original.GetEntier();

// ou encore mieux: SetEntier(Original.GetEntier() );

}

Pourquoi un passage par référence??

420-KAB-LG Programmation orientée par objets 39

(40)

passage par valeur…

void Test(A p) {

}

class A {

public:

A(A p);

};

int main() {

A a;

Test(a);

}

Appel de p.CtrCopie(a)

Appel de p.CtrCopie(a)

Appel de p.CtrCopie(a)

Appel de p.CtrCopie(a)

Appel de p.CtrCopie(a)

(41)

 Un paramètre déclaré const indique qu’il ne pourra pas être modifié à l’intérieur de la méthode.

 On peut aussi déclarer un objet local constant.

 Sur les objets et les paramètres const, on ne peut appeler que des méthodes const, pour respecter la garantie!

 Exemple:

CEntierEncapsule::CEntierEncapsule(const CEntierEncapsule& Original)

420-KAB-LG Programmation orientée par objets 41

(42)

Le const est un virus…

class CRect {

int x_,y_;

public:

CRect(const CRect& Autre);

void GetX() ; void GetY() ; };

CRect::CRect(const CRect& Autre) {

x_ = Autre.GetX();

}

Erreur: impossible de convertir un pointeur 'this' de 'const

CRect&' en ‘CRect&'

(43)

Le destructeur

 N’a pas de valeur de retour

 A le même nom que la classe préfixé du symbole ~

 Effectue les instructions appropriées lorsque l’objet est détruit

– Fermeture d’un fichier

– Destruction de mémoire allouée dynamiquement

 Pour l’instant, le service par défaut fera l’affaire!

420-KAB-LG Programmation orientée par objets 43

(44)

Le destructeur (suite)

class CEntierEncapsule {

public:

~CEntierEncapsule();

};

CEntierEncapsule::~CEntierEncapsule() {

cout << "Rien à faire pour l’instant…" << endl;

}

int main() {

CEntierEncapsule UnObjet(99);

cout << UnObjet.GetEntier() << endl;

} Appel automatique du destructeur!

(45)

 Dès qu’au moins un constructeur est défini, le service de construction par défaut disparait!

 Un constructeur sans paramètre est souvent essentiel (tableaux, composition, héritage, etc.)

 Attention de ne pas créer des situations ambiguës:

class CPasClair {

CPasClair();

CPasClair(int i=3);

};

int main() {

CPasClair a; // error C2668: 'CPasClair::CPasClair' : // appel ambigu à une fonction surchargée }

420-KAB-LG Programmation orientée par objets 45

(46)

Chapitre 3

Les relations

(47)

Diagramme de classes UML

420-KAB-LG Programmation orientée par objets 47

(48)

Relations entre les classes

 Il existe plusieurs types de relations entre deux classes:

– Aucune relation

Classes complètement indépendantes

– Utilisation

Simple dépendance: paramètre,

variable locale ou valeur de retour

(49)

(suite)

– Composition

– Agrégation

– Héritage

420-KAB-LG Programmation orientée par objets 49

(50)

La relation crée une dépendance

 La classe A qui a une relation avec la classe B devient dépendante de cette dernière

 Une classe dépendante d’une autre classe fait des #include « B.h »

 La modification d’une classe

– provoque normalement la recompilation des classes dépendantes (erreurs?)

– Peut amener un mauvais fonctionnement des

classes dépendantes

(51)

Première relation:

L’utilisation

420-KAB-LG Programmation orientée par objets 51

(52)

L’utilisation

 Une classe peut utiliser une autre classe de trois façons:

– En paramètre d’une méthode

– En variable locale dans une méthode

– En valeur de retour d’une méthode

(53)

…en paramètre

type A::Methode(B b) type A::Methode(B& b)

type A::Methode(const B& b) Exemples:

bool CBanque::Bloquer(CCompte c);

void CConsole::

Afficher(const string& Message);

void CFenetre::Afficher

(CImage& Image, int x, int y);

420-KAB-LG Programmation orientée par objets 53

Copie!

(54)

… en variable locale

type A::Methode() {

B b;

}

bool CResto::Payer(float Montant) {

CFacture Facture(Montant);

Facture.Imprimer();

//…

}

(55)

… en valeur de retour

B A::Methode() {

B b;

// …

return b;

}

Exemple:

COeuf CPoule::Pondre() {

COeuf UnOeuf;

// …

return UnOeuf;

}

420-KAB-LG Programmation orientée par objets 55

Copie!

Copie!

(56)

Deuxième relation:

La composition

(57)

class CAuto {

public:

CAuto();

~CAuto();

int GetNbChevaux() const;

void SetNbChevaux(int NbChevaux);

void DegonflerUneRoue(int i);

private:

int NbChevauxDuMoteur_;

int PressionDesRoues_[4];

};

420-KAB-LG Programmation orientée par objets 57

(58)

Classes CRoue et CMoteur

CRoue

-Pression_:int +Dégonfler()

CMoteur -NbChevaux_:int

+GetNbChevaux():int

+SetNbChevaux(entrée NbChevaux:int)

(59)

Classe CAuto améliorée

420-KAB-LG Programmation orientée par objets 59

class CAuto {

public:

CAuto();

~CAuto();

CRoue& GetRoue(int Index);

void Modifier(int NbChevaux);

private:

CMoteur& GetMoteur();

CMoteur SuperMoteur_;

CRoue Roues_[4];

};

(60)

La composition

 La composition est un type de relation entre deux classes qui implique une notion de

contenance.

 On dit que A et B sont deux classes reliées par une relation de composition, c’est-à-dire que A est composée de B

 A = Composée ; B= Composant

(61)

La composition

Exemples:

 Un objet Auto se compose d’objets moteur et roues.

 Un objet Hôtel se compose d’objets ChambreHôtel

 Un objet Ordinateur se compose d’objets CPU, clavier et écran

 Un objet mammifère se compose d’objets tête, 4 pattes

420-KAB-LG Programmation orientée par objets 61

(62)

La composition

 Le composant est utilisé comme attribut du composé.

 Les cycles de vie du composé et ses composants sont intimement liés.

 Il s’agit d’une agrégation forte: si le

composé est détruit, ses composants

disparaissent aussi

(63)

Construction / destruction d’une composition

 Si un objet B est un attribut de l’objet A, le constructeur de l’objet B sera appelé avant celui de l’objet A.

 Ceci est logique: pour construire une auto, il faut d’abord construire ses composantes,

comme le moteur et les roues.

420-KAB-LG Programmation orientée par objets 63

Raison: Accès possible

(64)

Construction / destruction d’une composition

 Lors de la destruction c’est l’inverse

 Si on veut utiliser un autre constructeur que le constructeur par défaut (ou mixte), on peut

sélectionner le constructeur à utiliser lors de la

pré-construction

(65)

La pré-construction

CAuto::CAuto() : SuperMoteur_(90) {

cout << "Constructeur de CAuto" <<

endl;

}

On peut même utiliser cette syntaxe pour initialiser tous les attributs :

CChat::CChat(int Age, string Nom) : Age_(Age), Nom_(Nom) { }

420-KAB-LG Programmation orientée par objets 65

(66)

Agrégation forte vs faible

 Agrégation forte = Composition

 Agrégation faible : Le composant ne disparaît pas si le composé est détruit.

 Exemples: (Aéroport et avions), (Train et

wagons), (groupe et étudiants), (Ferme et

animaux)

(67)

Représentation UML de la composition

420-KAB-LG Programmation orientée par objets 67

(68)

L’encapsulation appliquée à la composition

class CAuto {

public:

CAuto();

~CAuto();

const CRoue& GetRoue(int Index);

void Modifier(int NbChevaux);

private:

CMoteur& GetMoteur();

CMoteur SuperMoteur_;

CRoue Roues_[NBROUES];

};

Pas d’accès direct au moteur

(69)

Exécution du programme Auto

420-KAB-LG Programmation orientée par objets 69

(70)

Troisième relation:

L’héritage

( 2 e grand principe de la POO)

(71)

Motivation

420-KAB-LG Programmation orientée par objets 71

(72)

Généralisation

Classe de base, parent

ou générale Classes

dérivées, enfants ou spécialisées

Dérive de...

Hérite de...

Est une...

Is a…

(73)

L’Héritage

 L’héritage offre la possibilité de créer une classe à partir d’une autre.

 La nouvelle classe bénéficie des attributs et des méthodes de la classe dont elle

dérive. On dira alors que la classe enfant hérite du parent ou que la classe dérivée hérite de la classe de base. Dans la classe dérivée, on peut définir de nouveaux

membres afin de modifier et de spécialiser la classe de base.

420-KAB-LG Programmation orientée par objets 73

(74)

Déclaration de CPersonne

class CPersonne {

int Age_;

public:

CPersonne(int Age);

~CPersonne();

int GetAge() const;

void SeDéplacer();

};

Classe normale,

rien ne change!

(75)

class CEtudiant : public CPersonne {

int Note_;

public:

CEtudiant(int Age, int Note);

~CEtudiant();

int GetNote() const;

void Etudier();

};

420-KAB-LG Programmation orientée par objets 75

Indique que la

classe dérive

de CPersonne

(76)

Déclaration de Enseignant

class CEnseignant : public CPersonne

{

int Salaire_;

public:

CEnseignant(int Age, int Salaire);

~CEnseignant();

int GetSalaire() const;

void Enseigner();

};

Indique que la

classe dérive

de CPersonne

(77)

int main() {

CEtudiant Paul(19, 85);

Paul.Etudier();

cout << Paul.GetNote();

Paul.SeDéplacer();

cout << Paul.GetAge();

CEnseignant Joan(35, 15000);

Joan.Enseigner();

cout << Joan.GetSalaire();

Joan.SeDéplacer();

cout << Joan.GetAge();

}

420-KAB-LG Programmation orientée par objets 77

Méthodes héritées de

la classe parent

Méthodes héritées de

la classe

parent

(78)

Les modificateurs d’accès

 Les membres publics d’une classe sont utilisables par toutes les fonctions.

 Les membres privés d’une classe sont utilisables uniquement par les fonctions membres de cette classe.

 Les membres protégés d’une classe sont

utilisables par les fonctions membres de

cette classe ou d’une classe dérivée.

(79)

420-KAB-LG Programmation orientée par objets 79

(80)

Construction et destruction

Lors de la création d’un objet de la classe CEtudiant, il y a deux constructeurs

impliqués. Lorsqu’un objet CEtudiant est détruit, il y a deux destructeurs qui

participent à la destruction de l’objet.

1. Quel est l’ordre d’appel des constructeurs et des destructeurs?

2. Comment faire pour déterminer cet ordre?

3. Pourquoi cet ordre précis?

(81)

La pré-construction

 Lors de la pré-construction, on peut sélectionner le constructeur de la classe de base à utiliser pour acheminer de l’information à la classe de base:

CEtudiant::CEtudiant(int Age, int Note): CPersonne(Age)

{

SetNote(Note);

}

 La pré-construction peut aussi servir à

sélectionner les constructeurs à utiliser lors de la construction d’un composé.

420-KAB-LG Programmation orientée par objets 81

(82)

Chapitre 4

Pointeurs, allocation dynamique et

références

(83)

420-KAB-LG Programmation orientée par objets 8383

Les pointeurs

(indirection, raccourci, référence) 0x20

0x24

5

0x20

(84)

Les adresses

 On accède à l’adresse d’une variable (sa position en mémoire) avec le symbole &

 On accède au contenu d’une adresse avec le symbole *

int a = 3;

cout << a; // Affiche 3

cout << &a; // Affiche 0068FDF4

cout << *(&a); // Affiche 3, *(&a) = a

La variable a peut être de type primitif (int, char, …) ou un objet

* &

(85)

Les pointeurs

Un pointeur contient l’adresse d’une variable ou d’un objet.

 Déclaration d’un pointeur:

int* p; // Pointeur vers un int

CEntier* pEntier; // Pointeur vers un CEntier short a, *b; // a est un short, b est

// pointeur vers un short

420-KAB-LG Programmation orientée par objets 85

(86)

Exemple d’utilisation d’un pointeur (1)

short a, *b;

*a = 5; // invalide: a n’est pas un // pointeur

b = &a; // valide: b est un pointeur de

// short, et &a est l'adresse d'un // short

*b = 5; // valide: b est un pointeur de

// short. Cette opération a pour

// effet de déposer la valeur 5

// là où pointe b... donc dans a

(87)

Exemple d’utilisation d’un pointeur (2)

int a, // valeur de a: indéterminée b= 3; // valeur de b: 3

int *p; // p est un pointeur vers un int p= &a; // p reçoit l’adresse de a

// donc p pointe vers a

*p= 4; // le contenu pointé par p // ( donc a ) reçoit 4

b+= a; // b devient égal à 7!

420-KAB-LG Programmation orientée par objets 87

(88)

Visualiser les pointeurs

int a, b= 3;

int *p;

p= &a;

*p= 4;

(89)

Initialiser un pointeur

int *p = nullptr;

// (…)

if (p != nullptr) {

// ... p mène à un endroit valide }

else {

// ... utiliser *p serait imprudent!

...

}

420-KAB-LG Programmation orientée par objets 89

En C, on utilisait la constante NULL En C++ on utilisait l’adresse 0 (zéro)

En C++11, on utilise nullptr

(90)

Déclaration vs instruction

Déclaration Instruction

* Déclare un pointeur int *p;

void fonction(int *p);

Ce qui est pointé par cout << *p;

a = *p;

Fonction(*p);

& Déclare une référence int &r = i;

void fonction(int& r);

L’adresse de cout << &i;

Fonction(&i);

(91)

Pointeurs et POO

CEntier UnEntier(4);

// Affiche 4

cout << UnEntier.GetEntier();

// Affiche 0072AB00 cout << &UnEntier;

// Affiche 4

cout << (*(&UnEntier)).GetEntier();

420-KAB-LG Programmation orientée par objets 91

(92)

Pointeurs et POO (suite)

// Déclaration d’un pointeur vers un // objet

CEntier *pEntier = nullptr;

// Allocation dynamique d’un objet pEntier = new CEntier(3);

// Appel des méthodes de l’objet pointé // par pEntier

(*pEntier).SetEntier(3);

cout << (*pEntier).GetEntier() << endl;

(93)

L’opérateur ->

 L’opérateur -> est une syntaxe abrégée qui permet de sélectionner un membre d’un

objet pointé par un pointeur:

(*pEntier).SetEntier(3);

est identique à

pEntier->SetEntier(3);

420-KAB-LG Programmation orientée par objets 93

(94)

Passer un pointeur en paramètre

void Afficher(CEntier* pEntier) {

cout << pEntier->GetEntier();

}

int main() {

CEntier Entier(3);

CEntier *pEntier = new CEntier(4);

Afficher(&Entier);

Afficher(pEntier);

}

(95)

Passer un pointeur en paramètre (suite)

 Très similaire au passage par référence

 Il n’y a pas de copie d’objets effectués

 Les modifications apportées à l’objet dans la méthode ou la fonction se répercuteront à l’extérieur de la méthode ou de la

fonction.

Cependant, contrairement à la

référence, un pointeur peut être nul ou invalide.

420-KAB-LG Programmation orientée par objets 95

(96)

Retourner un pointeur

CEntier* Creer(int Valeur) {

return new CEntier(Valeur);

}

int main() {

CEntier *pEntier = Creer(5);

cout << pEntier->GetEntier();

}

(97)

Erreur à ne jamais faire! (1)

CEntier* Creer(int Valeur) {

CEntier EntierLocal(Valeur);

return &EntierLocal;

}

int main() {

CEntier *pEntier = Creer(5);

cout << pEntier->GetEntier();

}

420-KAB-LG Programmation orientée par objets 97

(98)

Détruire un objet créé dynamiquement

int main() {

CEntier *pEntier = new CEntier(6);

cout << pEntier->GetEntier();

// …

delete pEntier;

}

 Il est de bon usage que celui qui crée un

objet soit responsable de le détruire.

(99)

Erreur à ne jamais faire! (2)

CEntier Entier(3);

CEntier *pEntier = nullptr;

CEntier *pEntier2 = nullptr;

pEntier = &Entier;

pEntier2 = pEntier;

delete pEntier;

delete pEntier2;

420-KAB-LG Programmation orientée par objets 99

(100)

Pile vs Tas

int main() {

int i = 2;

CEtudiant *p = nullptr;

p = new CEtudiant();

test(i);

delete p;

}

void test(int j) {

cout << j;

}

Pile

2 (i) 2 (i) null (p) null (p)

CEtudiant CEtudiant

2 (j)

2 (j)

0xBB 0xBB (p) 0xBB (p)

(101)

420-KAB-LG Programmation orientée par objets 101 420-KAB-LG Programmation orientée par objets 101

L’allocation dynamique

(et application du cycle de vie)

(102)

Le tableau automatique (rappel)

 La taille du tableau doit être connue à la compilation:

int TabEntiers [ 100 ];

 Encore mieux:

const int NbCases = 100;

int TabEntiers [ NbCases ];

(103)

Exemples qui ne compilent pas

 Exemple 1:

int NbCases = 15;

int TabValeurs [ NbCases ];

 Exemple 2:

int NbCases;

cin >> NbCases;

int TabValeurs [ NbCases ];

 Exemple 3:

void CreerTableau(int Taille) {

const int TAILLE = Taille;

int Tableau[TAILLE];

}

420-KAB-LG Programmation orientée par objets 103

(104)

Le tableau dynamique

 Un tableau dynamique peut avoir une taille différente à chaque exécution

 L’espace mémoire est réservé à l’exécution et non à la compilation comme un tableau automatique

 Le tableau est alloué sur le tas et non sur la pile

 L’utilisation d’un tableau dynamique se fait en 5 étapes:

1. Déclaration d’un pointeur pour contenir l’adresse mémoire (le point de départ) du tableau

2. Réservation de l’espace mémoire avec l’opérateur new []

3. Conserver la taille du tableau dans une variable

4. Utiliser le tableau comme s’il était un tableau automatique 5. Lorsque le tableau n’est plus requis, libérer l'espace en

mémoire avec l’opérateur delete [ ]

(105)

int NbCases; // Taille du tableau

int *TabEntiers; // Pointeur pour retenir l’adresse // du tableau dynamique.

cin >> NbCases; // Demander la taille à l’usager

// Allocation de la mémoire et affectation de l’adresse TabEntiers = new int [NbCases];

// Utilisation du tableau

for (int i = 0; i < NbCases; i++) {

TabEntiers[i] = i * i;

cout << TabEntiers[i] << endl;

}

// Destruction de la mémoire allouée.

delete [] TabEntiers;

420-KAB-LG Programmation orientée par objets 105

(106)

Automatique vs dynamique

int main() {

const int Nb=10;

int Tab[Nb];

// utilisation …

}

int main() {

int Nb=10;

int* Tab = new int[Nb];

// utilisation … delete [] Tab;

}

(107)

 Les tableaux automatiques

– De types primitifs: int Notes[10];

– De type utilisateurs

De structures: Compte MesComptes[10];

De classes: CTasse MesTasses[10];

– De pointeurs: CTasse* MesTassesPtr[10];

C’est toujours la même syntaxe:

Type Nom[Taille];

420-KAB-LG Programmation orientée par objets 107

(108)

Les tableaux - Résumé

 Les tableaux dynamiques

– De types primitifs

int* Tab = new int [10]; … delete [] Tab;

– De type utilisateurs

De structures

Point* Flocs = new Point [10]; … delete [] Flocs;

De classes

CTasse* Tasses = new CTasse[10]; … delete [] Tasses;

– De pointeurs!

CTasse** Tasses = new CTasse*[10]; … delete [] Tasses;

C’est toujours la même syntaxe:

Type* Nom = new Type[Taille]; … delete [] Nom;

!

(109)

Les tableaux d’objets

 Lorsqu’on déclare un tableau d’objets:

CMenu* MesMenus = new CMenu[10];

Ou

CMenu MesMenus[10];

 Il y a appel du constructeur par défaut pour chaque élément du tableau

 Si aucun constructeur n’est défini: utilisation du constructeur automatique

 Si un constructeur est défini, mais pas le

constructeur par défaut: erreur de compilation!

(le constructeur de copie échappe à cette règle)

420-KAB-LG Programmation orientée par objets 109

(110)

La fuite mémoire

 Défaut de programmation grave et difficile à trouver!

 Outils de vérification de code (BoundsChecker)

 Exemple:

void Test() {

int* Tab = new int[10];

// … }

for(int i=0;i<1000000000;i++) char *c = new char[10];

Le delete [] a été oublié!

Ne pas essayer à la maison …

(111)

Retour sur les tableaux d'objets

Exemple 1 - Un objet

int main() {

CSou Sou;

Sou.Deplacer();

}

420-KAB-LG Programmation orientée par objets 111

Appel d'un constructeur

Appel du destructeur

Objet sur la

Pile

(112)

Exemple 2 - Un tableau automatique d’objets

int main() {

const int Nb = 5;

CSou Sou[Nb];

for(int i=0;i<NB;i++) {

Sou[i].Deplacer();

} }

Appels des constructeurs par défaut

Appels des destructeurs

Tableau sur la

Pile

(113)

Exemple 3 - Un tableau dynamique d’objets

int main() {

int Nb = 5;

CSou* pSou = new CSou[Nb];

for(int i=0;i<Nb;i++) {

pSou[i].Deplacer();

}

delete[] pSou;

}

420-KAB-LG Programmation orientée par objets 113

Appels des constructeurs par défaut

Appels des destructeurs Tableau

dans le

tas

(114)

Exemple 4 - Un pointeur d’objet

int main() {

CSou* pSou = new CSou;

pSou->Deplacer();

delete pSou;

}

Un objet ou un tableau dans le tas n'est pas détruit automatiquement lorsque la fonction se termine, il faut s'assurer de toujours garder un pointeur...

Appel d'un constructeur

Objet dans le

tas

Appel du destructeur

(115)

automatique de pointeurs d’objets (ex 4.8)

int main() {

const int Nb = 5;

CSou* pSou[Nb];

for(int i=0;i<Nb;i++) pSou[i] = new CSou;

for(int i=0;i<Nb;i++) pSou[i]->Deplacer();

for(int i=0;i<Nb;i++) delete pSou[i];

}

420-KAB-LG Programmation orientée par objets 115

Appel d'un constructeur Objets dans le

tas

Appel du destructeur Tableau de pointeurs

sur la pile

(116)

Exemple 6 - Un tableau dynamique de pointeurs d’objets (optionnel)

int main() {

int Nb = 5;

CSou** pSou;

pSou = new CSou*[Nb];

for(int i=0;i<Nb;i++) pSou[i] = new CSou;

for(int i=0;i<Nb;i++) pSou[i]->Deplacer();

for(int i=0;i<Nb;i++) delete pSou[i];

delete[] pSou;

}

Appel d'un constructeur

Appel du destructeur Tableau de pointeurs

dans le tas

Objets dans le tas

(117)

CTabEntiers::CTabEntiers(int Taille) { Table_ = new int[Taille];

Taille_ = Taille;

}

CTabEntiers::~CTabEntiers() { delete [] Table_;

}

void CTabEntiers::SetElement(int Index, int Entier) {

Table_[Index] = Entier;

}

int CTabEntiers::GetElement(int Index) const {

return Table_[Index];

}

420-KAB-LG Programmation orientée par objets 117

(118)

(suite)

Que se passes-t-il lorsqu’on passe un objet de la classe CTabEntiers en paramètre par valeur?

int main() {

CTabEntiers Tab(3);

Test(Tab);

}

Que se passe-t-il lorsqu’on construit un objet de la classe CTabEntiers à partir d’un autre?

int main() {

CTabEntiers Tab1(20);

CTabEntiers Tab2(Tab1);

void Test(CTabEntiers Param) {

// …

} Boum!

Re-

Boum!

(119)

Encapsulation d’un tableau d’entiers (suite)

Il faut donc absolument définir le constructeur de copie et l’opérateur d’affectation de la classe CTabEntiers:

public:

CTabEntiers(const CTabEntiers& Original);

CTabEntiers& operator=(const CTabEntiers&

Original);

420-KAB-LG Programmation orientée par objets 119

La trinité

Constructeur de copie Opérateur d’affectation

Destructeur

(120)

Encapsulation d’un tableau d’entiers

Afin de compléter les fonctionnalités de la classe CTabEntiers, pouvez-vous écrire une méthode qui permettra de modifier la taille du tableau?

public:

void ModifierTaille(int NouvelleTaille,

bool ConserverValeurs);

(121)

420-KAB-LG Programmation orientée par objets 121121

Les références

&

(122)

Les références

 Tout comme le pointeur, la référence représente l’adresse d’un objet

 Contrairement au pointeur, la référence ne

référera qu’à une seule et même chose tout au long de son existence, et devra conséquemment référer à quelque chose dès sa déclaration.

 On déclare une référence en préfixant son nom d’un “&”. Une référence peut être considérée comme étant au même endroit, en mémoire, que ce à quoi elle réfère. C’est un synonyme, un

alias.

(123)

Les références (exemple)

int main () {

int i = 5; // i est un int de valeur 5 int *p = 0; // p pointe « nulle part » ! int &r = i; // r est une réference à i

i++; // i devient 6, r aussi (car r // réfère à i)

r++; // i devient 7, r aussi p = &i; // p pointe vers i

(*p)++; // i, r et *p deviennent 8 p = &r; // p pointe là où r réfère (p

// pointe vers i) }

420-KAB-LG Programmation orientée par objets 123

(124)

Paramètre et retour par référence d’un objet

CEntier ParValeur(CEntier Param) {

Param.SetEntier(3);

return Param;

}

CEntier& ParReference(CEntier& Param) {

Param.SetEntier(3);

return Param;

}

(125)

Paramètre et retour par

référence d’un objet (suite)

CEntier Entier(1);

for(int i=0;i<1000;++i) {

// 2000 copies d’objets effectuées // 1000 affectations

Entier = ParValeur(Entier);

}

for(int i=0;i<1000;++i) {

// 0 copie d’objet effectuée

// 1000 affectations (qui pourraient être évitées) Entier = ParReference(Entier);

}

420-KAB-LG Programmation orientée par objets 125

(126)

void ParValeur(CEntier Param) {

Param.SetEntier(3);

}

void ParReference(CEntier& Param) {

Param.SetEntier(3);

}

int main () {

CEntier Entier(1);

ParValeur(Entier);

cout << Entier.GetEntier(); // Ceci affiche 1 ParReference (Entier);

cout << Entier.GetEntier(); // Ceci affiche 3

}

(127)

Les références constantes

int i = 5; // i est un int de valeur 5 const int *p = 0; // p pointe « nulle part »!

const int &r = i; // r est une référence à i i++; // i devient 6, r aussi

// (car r réfère à i)

r++; // INTERDIT!!!

p = &i; // p pointe vers i (*p)++; // INTERDIT!!!

p = &r; // p pointe là où r réfère // (p pointe vers i)

420-KAB-LG Programmation orientée par objets 127

(128)

Les références constantes et les objets

 Il est souvent préférable d’utiliser une référence constante plutôt que de faire un passage par copie.

 Une référence constante sur un objet interdit d’appeler une de ses méthodes qui n’est pas constante car seules les méthodes constantes garantissent que l’objet ne sera pas modifié.

void ReferenceConstante(const CEntier& Param) {

// INTERDIT si CEntier::SetEntier(int) // n’est pas const!

Param.SetEntier(3);

}

(129)

class CTableau {

CEntier Tableau_[10];

public :

// Le const permet de ne pas briser l’encapsulation!

const CEntier& GetElement(int Index);

void SetElement(int Index, int Entier);

};

int main () {

CTableau Tab;

// INTERDIT car CEntier::SetEntier(int) // n’est pas const

Tab.GetElement(0).SetEntier(3);

Tab.SetElement(0,3); // Ok!

}

420-KAB-LG Programmation orientée par objets 129

(130)

Chapitre 5 - Le polymorphisme

3 e grand principe de la POO

« Qui peut prendre plusieurs

formes »

(131)

La redéfinition de méthodes

 Redéfinition (override) != Surcharge (overload)

420-KAB-LG Programmation orientée par objets 131

(132)

La redéfinition de méthodes (suite)

 Méthodes avec la même signature, mais une définition différente:

void CPersonne::SeDéplacer() { cout << "Marcher";}

void CEtudiant::SeDéplacer()

{ cout << "Prendre son vélo";}

void CEnseignant::SeDéplacer()

{ cout << "Prendre sa BMW" ; }

(133)

La redéfinition de méthodes (suite)

 Les classes dérivées ont donc deux versions de la méthode SeDéplacer. Déterminez la version de la méthode utilisée dans les situations suivantes:

CPersonne John;

CEtudiant Bobby;

CEnseignant Joan;

John.SeDéplacer();

Bobby.SeDéplacer();

Joan.SeDéplacer();

420-KAB-LG Programmation orientée par objets 133

(134)

Les pointeurs d’objets

 Si on déclare un pointeur vers un int, ce pointeur doit pointer vers un int. Si on fait pointer le pointeur de int vers un char, on obtient une erreur de compilation :

int *p = new char;

main.cpp(86) : error C2440:

'initialisation' : impossible de convertir de 'char *' en 'int *'

 Pour atteindre le polymorphisme, cette règle doit être assouplie pour les objets:

Si on déclare un pointeur vers un objet de la classe

A, ce pointeur doit pointer vers un objet de la

classe A ou un objet d’une classe dérivée de A.

(135)

 Pouvez-vous déterminer les lignes qui provoquent une erreur de compilation?

CPersonne* Obj1 = new CPersonne;

CPersonne* Obj2 = new CEtudiant;

CPersonne* Obj3 = new CEnseignant;

CEtudiant* Obj4 = new CPersonne;

CEtudiant* Obj5 = new CEtudiant;

CEtudiant* Obj6 = new CEnseignant;

CEnseignant* Obj7 = new CPersonne;

CEnseignant* Obj8 = new CEtudiant;

CEnseignant* Obj9 = new CEnseignant;

 Il y a donc maintenant une différence entre le type de pointeur utilisé et le type réel de l’objet!!

420-KAB-LG Programmation orientée par objets 135

(136)

d’objets

 Déterminez la version de la méthode utilisée dans les exemples suivants:

CPersonne* Obj1 = new CPersonne;

CPersonne* Obj2 = new CEtudiant;

CPersonne* Obj3 = new CEnseignant;

CEtudiant* Obj5 = new CEtudiant;

CEnseignant* Obj9 = new CEnseignant;

Obj1->SeDéplacer();

Obj2->SeDéplacer();

Obj3->SeDéplacer();

Obj5->SeDéplacer();

Obj9->SeDéplacer();

 Par défaut, la version de la méthode utilisée est

déterminée par le type de pointeur utilisé.

(137)

(ou virtuelles)

 Idéalement, la version de la méthode utilisée

devrait être déterminée par le type réel de l’objet.

Pour ce faire, il faut ajouter le mot-clé virtual aux déclarations des méthodes:

class CPersonne {

// …

virtual void SeDéplacer();

// … };

420-KAB-LG Programmation orientée par objets 137

(138)

Méthodes polymorphes (suite)

 En supposant que la méthode SeDéplacer est virtuelle, déterminez la version de la méthode utilisée dans les exemples suivants:

CPersonne *Obj1 = new CPersonne;

CPersonne *Obj2 = new CEtudiant;

CPersonne *Obj3 = new CEnseignant;

CEtudiant *Obj5 = new CEtudiant;

CEnseignant *Obj9 = new CEnseignant;

Obj1->SeDéplacer();

Obj2->SeDéplacer();

Obj3->SeDéplacer();

Obj5->SeDéplacer();

Obj9->SeDéplacer();

(139)

int main() {

const int N=100;

CPersonne* Tab[N]; // Tableau de pointeurs for(int i=0;i<N;++i)

{

// Le type d’objet alloué est aléatoire!

if(rand()%2==0) Tab[i] = new CEtudiant;

else Tab[i] = new CEnseignant;

}

// La méthode SeDeplacer change selon

// le type réel de l’objet (plusieurs formes)

for(int i=0;i<N;++i)

Tab[i]->SeDéplacer();

for(int i=0;i<N;++i) delete Tab[i];

}

420-KAB-LG Programmation orientée par objets 139

Ces deux simples petits lignes illustrent

toute la beauté du

polymorphisme!

(140)

Appeler la méthode de la classe de base

 Pour effectuer une partie du traitement, la méthode d’une classe dérivée peut appeler la méthode de la classe de base:

void CEtudiant::SeDéplacer() {

// …

// Pour éviter la confusion, il faut // spécifier le nom de la classe de base CPersonne::SeDéplacer();

//…

}

 Que se passe-t-il si on oublie le CPersonne:: ?

(141)

La méthode virtuelle pure et classe abstraite

 La méthode virtuelle pure n’a pas de définition dans la classe de base (=0)

class CPersonne {

virtual void SeDéplacer()=0;

};

 Il est donc obligatoire de redéfinir les méthodes virtuelles pures dans les classes dérivées

 On ne peut pas créer d’objets d’une classe qui possède une ou des méthodes virtuelles pures

 On dira donc de cette classe qu’elle est abstraite

420-KAB-LG Programmation orientée par objets 141

(142)

Chapitre 6 – Bibliothèque standard de C++

1. Les entrées / sorties (istream, ostream)

2. Les fichiers (ifstream, ofstream)

3. Les chaînes de caractères (string)

(143)

 Ensemble de classes et de fonctions standards

 Contient aussi la bibliothèque standard du C

 Contient la STL (Standard Template Library)

 Fait partie de la norme ISO du C++11

 Elle contient différents modules:

Entrées/sorties

Chaînes de caractères – Structures de données – Algorithmes

– Temps, tâches, etc.

 using namespace std;

420-KAB-LG Programmation orientée par objets 143

Ensemble de

classes,

constantes,

fonctions, etc.

(144)

Hiérarchie des classes E/S

Références

Documents relatifs

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

Point p2=p1 ; // constructeur de recopie : création de l’objet p2 // et son initialisation avec les données de p1.. Attention : il faut différencier entre recopie et

Une classe A utilise une autre classe B si elle déclare en son sein une ou plusieurs entités de la classe B et en appelle les méthodes.. On dit aussi que la classe A est cliente de

On appelle type abstrait de données (TAD) un ensemble d'objets caractérisés par les opérations qui leur sont tous applicables... TYPE ABSTRAIT

Fonction C normale qui jouit du privilège d'avoir accès aux membres privés d'une classe.. ✔ On la déclare friend au sein de

Cette implémentation s'est en fait contenté, avec super.clone(); , de faire appel à la méthode clone() héritée de Object , qui crée un objet de la même classe que l'original

Comme dans le cas d’une méthode, si le code est très court, on peut directement mettre le constructeur dans la déclaration de la classe (définition en ligne). Exemple :

Cette technique permet de sécurisé l’accès aux données en vérifiant par exemple des conditions de valeur ou d’accès et permettant une plus grande flexibilité du coeur des