• Aucun résultat trouvé

Conséquences – affectations possibles

Dans le document Programmation orientée objet avec C++ (Page 47-63)

public:

. . .

void AfficherCaracteristiques() const;

};

• Définition

void Condensateur::AfficherCaracteristiques() const {

ComposantPassif::AfficherCaracteristiques();

cout << "Capacite : " << capacite * 1.0e6 << " uF" << endl;

}

• Résultat

Programmation orientée objet en C++

Héritage – Représentation en mémoire

ComposantPassif string nom

Condensateur string nom

double capacite

Organisation en mémoire identique

Conséquences – affectations possibles

compo1 = c1; // Ok, définit entièrement compo1

c1 = compo1; // Interdit, ne définit pas complètement c1

Introduction à la programmation orientée objet avec C++ 94

Les méthodes virtuelles et le polymorphisme - Introduction

• On souhaite écrire une fonction

– Calculant et affichant les valeurs d’impédances à toutes les décades (1, 10, 100, 1000, 10000 Hz…)

– Utilisable avec tous types d’impédances

• Résistances, Condensateurs, Inductances, autres…

• Prototype pour une résistance

void AfficherValeursImpedance(const Resistance & composant);

• Prototype pour un condensateur

void AfficherValeursImpedance(const Condensateur & composant);

• Prototype pour une inductance

void AfficherValeursImpedance(const Inductance & composant);

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme - Introduction

• Implémentation : 3 fois le même code !

void AfficherImpedance(const Resistance & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

frequence = frequence * 10;

} }

void AfficherImpedance(const Condensateur & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

frequence = frequence * 10;

} }

void AfficherImpedance(const Inductance & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

frequence = frequence * 10;

} }

Introduction à la programmation orientée objet avec C++ 96

Les méthodes virtuelles et le polymorphisme - Introduction int main()

{

Condensateur c1;

Inductance l1;

Resistance r1;

r1.DefinirNom("Resistance 1");

r1.DefinirResistance(1000);

c1.DefinirNom("Condensateur 1");

c1.DefinirCapacite(4.7e-6); // 4.7 µF l1.DefinirNom("Inductance 1");

l1.DefinirInductance(25e-3); // 25 mH AfficherImpedance(r1);

AfficherImpedance(c1);

AfficherImpedance(l1);

pause();

}

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme

• Solution pour éviter de répéter 3 fois le code ?

– Utiliser le type de base ComposantPassif comme paramètre.

– Résistance, Condensateur et Inductance héritent de ComposantPassif.

• Problème

– « CalculerImpedance » n’est pas déclarée sur ComposantPassif !

void AfficherImpedance(const ComposantPassif & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl; + AfficherCaracteristiques() : void

Induc tance - inductance : double

+ CalculerImpedance(double) : Complexe

Introduction à la programmation orientée objet avec C++ 98

Les méthodes virtuelles et le polymorphisme

• Déclarer CalculerImpedance pour la classe parent

class ComposantPassif {

public:

. . . .

Complexe CalculerImpedance(double frequence) const;

};

Complexe ComposantPassif::CalculerImpedance(double frequence) const {

Complexe resultat;

resultat.DefinirCartesien(0.0, 0.0);

return resultat;

}

• On choisit de retourner 0, car on ne sait pas comment calculer dans la classe ComposantPassif.

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme – Test

void AfficherImpedance(const ComposantPassif & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

r1.DefinirNom("Resistance 1");

r1.DefinirResistance(1000);

c1.DefinirNom("Condensateur 1");

c1.DefinirCapacite(4.7e-6); // 4.7 µF l1.DefinirNom("Inductance 1");

l1.DefinirInductance(25e-3); // 25 mH AfficherImpedance(r1);

AfficherImpedance(c1);

AfficherImpedance(l1);

pause();

}

Introduction à la programmation orientée objet avec C++ 100

Les méthodes virtuelles et le polymorphisme – Observations

• Fonctionnement non satisfaisant

– AfficherCaracteristiques

• C’est la méthode de base de ComposantPassif qui est appelée.

• Elle n’affiche que le nom du composant, pas ses valeurs.

– CalculerImpedance

• C’est la méthode de base de ComposantPassif qui est appelée.

• Elle retourne toujours 0.

• Comportement souhaitable

– En fonction de la classe du composant passé en paramètre.

– Appeler la fonction AfficherCaracteristiques de cette classe.

– Appeler la fonction CalculerImpedance de cette classe.

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme

• Appel d’une méthode normale

– La méthode appelée est celle associée au type de la déclaration – Cette méthode est choisie au moment de la compilation.

• Appel d’une méthode virtuelle

– La méthode appelée est celle associée au type effectif de l’objet passé en paramètre.

– Cette méthode est choisie au moment de l’exécution.

• Syntaxe

– Pour qu’une méthode soit virtuelle, il suffit de faire précéder sa déclaration par le mot réservé « virtual ».

– En C++, cette déclaration est requise seulement à la première apparition de la méthode (dans la classe de base).

Introduction à la programmation orientée objet avec C++ 102

Les méthodes virtuelles et le polymorphisme

• Modification minime de l’exemple précédent

class ComposantPassif {

private:

string nom;

public:

void DefinirNom(const string & valeur);

string LireNom() const;

virtual void AfficherCaracteristiques() const;

virtual Complexe CalculerImpedance(double frequence) const;

};

• Exécution conforme aux attentes

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme

• Avec la déclaration virtual

– La fonction CalculerImpedance appelée est celle correspondant au type effectif de l’objet.

– Idem pour AfficherCaracteristiques.

void AfficherImpedance(const ComposantPassif & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

frequence = frequence * 10;

} }

Introduction à la programmation orientée objet avec C++ 104

Les méthodes virtuelles et le polymorphisme

void AfficherImpedance(const ComposantPassif & composant) {

double frequence = 1.0;

Complexe impedance;

composant.AfficherCaracteristiques();

while (frequence <= 1.0e6) {

impedance = composant.CalculerImpedance(frequence);

cout << frequence << " Hz : " << impedance << endl;

frequence = frequence * 10;

} }

La méthode effectivement appelée derrière cet appel dépend du type effectif de l’objet.

La fonction AfficherImpedance s’adapte au type des objets manipulés.

Cette fonction peut être utilisée avec différents types, elle est dite polymorphe.

Le mécanisme utilisé s’appelle polymorphisme.

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme - Fonctionnement

• Une classe avec des méthodes virtuelles

– Comporte automatiquement une VMT : Virtual Method Table

– C’est un tableau contenant l’adresse de ses différentes méthodes virtuelles

• Un objet d’une classe avec méthodes virtuelles

– Comporte automatiquement un pointeur sur la VMT de sa classe (_vfptr, _vptr, _vmt)

class A

VMTComposant

Les méthodes virtuelles et le polymorphisme - Fonctionnement

Introduction à la programmation orientée objet avec C++ 106

ComposantPassif

VMTComposantPassif* __vmt;

VMTResistance

VMTInductance Resistance

VMTComposantPassif* __vmt;

Inductance

VMTComposantPassif* __vmt;

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme - Fonctionnement

• Appel d’une méthode virtuelle

– On accède à la VMT de la classe grâce au champs caché _vmt.

– On trouve l’adresse de la méthode dans la VMT par position

• Chaque méthode correspond à une position fixe

• Ex : VMT[0] : AfficherCaracteristiques

– On appelle la méthode se trouvant à cette adresse

• Coût

– Performances : 1 indirection, donc peu d’impact – Mémoire :

• Tables VMT répétées pour chaque classe.

• Code plus volumineux

• Problématique dans des environnements extrêmement contraints.

Les méthodes virtuelles et le polymorphisme - Fonctionnement

• Observation avec le debugger visual studio.

Inductance l1, l2;

Condensateur c1, c2;

Resistance r1, r2;

Introduction à la programmation orientée objet avec C++ 108

Programmation orientée objet en C++

Les méthodes virtuelles et le polymorphisme

• Classe ComposantPassif

– La déclaration de la méthode CalculerImpedance est requise pour permettre son appel sur les objets de ce type.

– Son implémentation retournant toujours 0 est inutile.

– Le seul intérêt est de déclarer l’ « interface » commune de la classe Composant Passif et de ses sous-classes.

• Méthode virtuelle pure (abstraite)

– Il est possible de déclarer la méthode sans l’implémenter.

– Elle est alors dite virtuelle pure ou abstraite.

– Il faut terminer la déclaration par « =0 ».

• Exemple

virtual Complexe CalculerImpedance(double frequence) const =0;

Introduction à la programmation orientée objet avec C++ 110

Polymorphisme avec des paramètres par adresse ou par référence

• Passage par adresse ou par référence

void AfficherImpedance(const ComposantPassif & composant);

– La fonction reçoit l’adresse du paramètre effectif.

– Permet d’aller consulter sa classe et d’appeler la bonne méthode virtuelle.

• Passage par valeur

void AfficherImpedance(const ComposantPassif composant);

– La fonction reçoit une copie du paramètre effectif.

– La copie est toujours de type ComposantPassif, pas du type effectif.

– Seules les méthodes de ComposantPassif seront appelées.

– Le mécanisme des méthodes virtuelles ne fonctionne pas !

Programmation orientée objet en C++

Une 3ème classe de visibilité

• Rappel

– public

• Méthodes et attributs utilisables depuis l’extérieur de la classe.

– private

• Méthodes et attributs utilisables depuis l’intérieur de la classe.

• Classe de visibilité supplémentaire

– protected : méthode et attributs utilisables

• Depuis l’intérieur de la classe.

• Depuis l’intérieur des sous classes.

Introduction à la programmation orientée objet avec C++ 112

Polymorphisme avec des listes d’objet

• Possibilité de construire des listes d’objets polymorphes

– Liste contenant des pointeurs sur des objets de différents types.

• Exemple : liste de pointeurs sur ComposantPassif

Resistance Resistance

Condensateur Liste de

ComposantPassif *

Inductance

Condensateur

Inductance

Condensateur Resistance

Condensateur

Programmation orientée objet en C++

Signification conceptuelle de l’héritage

• Quand est-il juste d’utiliser un héritage ?

– Si on peut dire de la sous-classe « EST UN » par rapport à son parent

ComposantPassif - nom: string

+ DefinirNom(st ring) : void + LireNom() : string + AfficherCaracteristiques() : void

Resis tance - resistance : double

+ CalculerImpedance(double) : Complexe

Induc tance - inductance : double

+ CalculerImpedance(double) : Complexe

Condensateur - capacite: double

+ CalculerImpedance(double) : Complexe

Introduction à la programmation orientée objet avec C++ 114

Principes de conception logicielle orientée objet

• Que signifie classe ?

– Classe = ensemble d’objets.

– Terme issu du domaine de la « Classification ».

– Sous-classe = sous-ensemble.

ComposantPassif - nom: string

+ DefinirNom(st ring) : void + LireNom() : string + AfficherCaracteristiques() : void

Resis tance - resistance : double

+ CalculerImpedance(double) : Complexe

Induc tance - inductance : double + CalculerImpedance(double) : Complexe

Condensateur - capacite: double

+ CalculerImpedance(double) : Complexe

Composant passif

Résistance

Inductance

Condensateur

Programmation orientée objet en C++

Principes de conception logicielle orientée objet - UML

EtreV iv ant

Végé tal Ani mal

Vertébrés Inv ertébré

Mamifères

Hum ain

• Conception orientée objet :

– Découpage d’un problème complexe en familles d’objets.

– Notion d’objet : identité, état, comportement.

– Notion assez intuitive.

• Caractéristique des logiciels conçus selon une approche Orientée Objet

– Résistent assez bien aux changements de spécifications.

– Aisément extensibles.

– Meilleure pérennité.

Introduction à la programmation orientée objet avec C++ 116

Concepts avancés – la généricité - introduction

• Exemple des classes de gestion de liste

– ListeDouble, ListeInt, ListeChar, ListComposantPassif, … – Le code est strictement identique.

– Seul le type des éléments change.

• Comment éviter de répéter le code pour chaque type ?

• C++ supporte la généricité

– Possibilité d’écrire des classes et fonctions.

– Dont l’implémentation est paramétrée par le type.

• Exemple

– List<double>

– List<int>

Le langage C++

Concepts avancés – la généricité – déclaration d’une classe générique

• Particularité

– La définition des méthodes doit aussi être visible lors de l’utilisation de la classe générique

– En général, placé aussi dans le .h

template <class ElementType, int Size>

class List { public:

List();

ElementType & operator[](int index);

int GetSize() const { return Size; } int GetCount() const;

int Add(const ElementType & value);

void Clear();

void RemoveAt(int index);

void Insert(int index, const ElementType & value);

private:

ElementType _elements[Size];

int _count;

};

Introduction à la programmation orientée objet avec C++ 118

Concepts avancés – la généricité – implémentation

template <class ElementType, int Size>

void List<ElementType, Size>::RemoveAt(int index) {

if (index >= 0 && index < _count) {

for (int i = index + 1 ; i < _count; i++) _elements[i - 1] = _elements[i];

_count = count - 1;

} else

throw Exception("Invalid index");

}

• Remarques

– Une classe générique est appelée « template » ou « patron ».

– C’est un moule paramétré permettant de générer des classes.

– La généricité peut aussi s’appliquer aux fonctions.

Le langage C++

Concepts avancés – la généricité – utilisation

List<double, 100> liste1;

List<int, 100> liste2;

liste1.Add(2.3);

liste2.Add(10);

Introduction à la programmation orientée objet avec C++ 120

Concepts avancés – la stl

• Le C++ est livré avec une bibliothèque de templates

– Stl : Standard Template Library.

– Avantages

• Comporte de nombreux conteneurs et algorithmes.

– Inconvénients

• Utilisation peu intuitive au début.

• Pas facile à étendre.

• Utilise l’allocation dynamique de mémoire.

• Difficilement utilisable dans les environnements temps réel.

Le langage C++

Concepts avancés – la stl - exemple

#include <iostream>

#include <vector>

using namespace std;

int main() {

vector<double> v;

v.push_back(1.1);

v.push_back(2.2);

v.push_back(3.3);

cout << "Taille: " << v.size() << endl;

cout << "Element[1]:" << v[1] << endl;

cout << "Boucle sur les elements:" << endl;

int i;

for(i=0; i < v.size(); i++) cout << v[i] << endl;

cout << endl << "Iterateur:" << endl;

vector<double>::const_iterator it;

for(it = v.begin() ; it != v.end() ; it++) cout << *it << endl;

Introduction à la programmation orientée objet avec C++ 122

Concepts avancés – la stl – aperçu du contenu

Le langage C++

Bibliothèque standard

• Bibliothèque standard du C++ : assez fournie.

– Chaînes de caractères.

– Entrées sorties, fichiers.

– Conteneurs génériques : Standard Template Library (STL)

• Vecteurs, listes, files, piles, …

• Largement documentée

Introduction à la programmation orientée objet avec C++ 124

Dans le document Programmation orientée objet avec C++ (Page 47-63)

Documents relatifs