8
L’héritage en C++ Philippe d’Anfray GIP RENATER 2006-2007 [email protected] Formation d’Ing ´ enieurs de l’Institut Galil ´ ee MACS 2 GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 1/30 Héritage/Définition (1) On peut dériver une classe à partir d’une autre. La classe dérivée hérite de toutes les caractéristiques de la classe dite de base. class BASE class DERIVEE : PUBLIC BASE { { int i, j; int k, l; ... ... public: public: void f_base (...); void f_derivee (...); ... ... }; }; ... On intéressera essentiellement à l’héritage “public”. GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 2/30 Héritage/Définition (2) Une instance de la classe dérivée possède en plus des siens toutes les données et toutes les méthodes de la classe de base. ... int main() { DERIVEE d1, d2; d1.f_base (...); // Possible, vient de BASE d1.f_derivee (..); // OK aussi vient de DERIVE } On peut redéfinir le comportement de l’objet en surchargeant les méthodes Attention. . . voir plus loin. . . GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 3/30 Héritage/Définition (3) Le processus peut se répéter, on obtient des graphes d’héritage Héritage simple: un arbre, Héritage multiple: graphe acyclique. Base Dérivé_2 Dérivé_1 Dérivé_3 Dérivé_4 Dérivé_2 Dérivé_1 Dérivé_3 Dérivé_4 Base_1 Base_2 Arbre d’héritage (simple) Graphe d’héritage (multiple) GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 4/30

2006 2007-heritage-en-c++

Embed Size (px)

Citation preview

Page 1: 2006 2007-heritage-en-c++

L’héritage en C++Philippe d’Anfray GIP RENATER

2006-2007

[email protected]

Formation d’Ingenieurs de l’Institut Galilee MACS 2

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 1/30

Héritage/Définition (1)

On peut dériver une classe à partir d’une autre. La classe dérivéehérite de toutes les caractéristiques de la classe dite de base.

class BASE class DERIVEE : PUBLIC BASE{ {

int i, j; int k, l;... ...public: public:void f_base (...); void f_derivee (...);... ...

}; };...

On intéressera essentiellement à l’héritage “public”.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 2/30

Héritage/Définition (2)

Une instance de la classe dérivée possède en plus des siens toutesles données et toutes les méthodes de la classe de base.

...int main(){DERIVEE d1, d2;d1.f_base (...); // Possible, vient de BASEd1.f_derivee (..); // OK aussi vient de DERIVE}

On peut redéfinir le comportement de l’objet en surchargeant lesméthodes

Attention . . . voir plus loin. . .

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 3/30

Héritage/Définition (3)

Le processus peut se répéter, on obtient des graphes d’héritageHéritage simple: un arbre,Héritage multiple: graphe acyclique.

Base

Dérivé_2Dérivé_1

Dérivé_3 Dérivé_4

Dérivé_2Dérivé_1 Dérivé_3

Dérivé_4

Base_1 Base_2

Arbre d’héritage (simple) Graphe d’héritage (multiple)

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 4/30

Page 2: 2006 2007-heritage-en-c++

Privé/Public (1)

Rappel: lors de la définition des objets, il y a toujours deux points devues et donc deux statuts possibles pour les champs:

le programmeur concepteur/développeur, partie “privée”;

le programmeur utilisateur, partie “public”.

Comment ces notions passent-elles à travers les mécanismesd’héritage ?

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 5/30

Privé/Public (2)

Règle générale:

La partie privée de la classe de base reste inaccessible à laclasse dérivée.

Le concepteur de DERIVEE n’a pas accès à la partie privée dela classe de BASE sauf si elle est déclarée explicitement amie.

Tout ce qui peut modifier la partie privée d’une classe doit êtredéclaré dans le corps de la classe.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 6/30

Privé/Public (3)

Cas de l’héritage “privé”, la partie publique de BASE devient privéepour DERIVEE. Le concepteur de DERIVEE y a accès pasl’utilisateur.

class BASE class DERIVEE:BASE{ {private://dev. BASE private:// dev. DERIVEE... ...public: //util. BASE public: // util. DERIVEE... //dev. DERIVEE ...}; };

Mais on s’intéresse plutôt à l’héritage “public”

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 7/30

Privé/Public (4)

La partie publique de BASE peut être rendus accessible auxutilisateurs de DERIVEE: héritage “public”.

class BASE class DERIVEE:public BASE{ {private://dev. BASE private:// dev. DERIVEE... ...public: //util. BASE public: // util. DERIVEE... //dev. DERIVEE ...... //util. DERIVEE };... //car public};

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 8/30

Page 3: 2006 2007-heritage-en-c++

Privé/Public (5)

Pour des raisons d’optimisations, le concepteur de DERIVEE asouvent besoin d’ accèder à la partie privée de BASE.

Cela donne lieu à deux types d’excès:

le tout ami : plus aucune protection;

le tout public: visibilité totale.

Problème: on perd la séparation spécification/réalisation !

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 9/30

Protégé (1)

Il existe un statut intermédiaire: le champ protégé:

class BASE class DERIVEE: public BASE{ private: //dev. BASE {... private:protected://dev. BASE ...... //dev. DERIVEE public:public: //util. BASE ...... //dev. DERIVEE };};

Un champ protégé de BASE est accessible aux développeurs deDERIVEE pas aux utilisateurs.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 10/30

Héritage / Fonctions amies (1)

Les relations d’amitié ne se transmettent pas par héritage.

class BASE class DERIVEE: public BASE{ {private: ... private:protected: ... ...public: public:friend void ff ...

(BASE& b...); ...... };

};

ff n’est pas amie de DERIVEE.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 11/30

Héritage/ Constructeurs-Destructeurs (1)

Deux règles simples:

Le constructeur de la classe de base si il existe est appelé avantle constructeur de la classe dérivée.

Le destructeur de la classe de base si il existe est appelé aprèsle destructeur de la classe dérivée.

Se généralise si il y a plusieurs dérivations.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 12/30

Page 4: 2006 2007-heritage-en-c++

Héritage/ Constructeurs-Destructeurs (2)

Un problème, celui des arguments:

class BASE class DERIVEE : public BASE{ ... { ...public: public:// avec arguments // avec argumentsBASE DERIVEE(int b_1...float b_n) (float d_1...char* d_m);{... ...} };

};

Je dois pouvoir utiliser DERIVEE sans a priori connaître BASE.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 13/30

Héritage/ Constructeurs-Destructeurs (3)

Quand je réalise le constructeur de DERIVEE je dois donner lesvaleurs des arguments du constructeur de BASE:

DERIVEE::DERIVEE (float d_1, ...char* d_m):BASE (val_b_1...val_b_n);

//// val_b_1...val_b_n sont les valeurs// des arguments b_1...b_n passes au// constructeur de la classe BASE// pour construire un objet DERIVEE

{... ;}

Les destructeurs n’ont pas d’argument, pas de problème(s).

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 14/30

Polymorphisme (1)

Je peux redéfinir une fonction:class BASE class DER:public BASE int main(){ { {... ... DER d;public: public: // ff de DERvoid ff(..); void ff (..); d.ff(..);... ... // ff de BASE}; }; d.BASE::ff(..);

}

Notez le come-back de l’opérateur ::Les redéfinitions de fonctions sont dangereuses à manipuler...

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 15/30

Polymorphisme (2)

Un pointeur sur une instance d’une classe dérivée peut êtreconsidéré comme un pointeur sur une instance de la classe de base.Dans l’autre sens le typage explicite est obligatoire .

main(){BASE *p_base;DERIVEE *p_derivee;...// licite du particulier au generalp_base = p_derivee;// du general au particulier: requete explicitep_derivee = (DERIVEE *) p_base;...}

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 16/30

Page 5: 2006 2007-heritage-en-c++

Fonctions virtuelles (1)

Soit une classe matrice_carree. Je sais définir les méthodes maisla forme des données n’est pas fixée à priori:

Matrice

Symétrique

Carrée

Matrice Matrice tridiagonale ...

.........

Matrice Pleine

On aura une réalisation différente pour chaque classe dérivée.notion d’archétype .

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 17/30

Fonctions virtuelles (2)

Fonction virtuelles:

class matrice_carree{

// donnees: pas les elementspublic:

virtual inverser(..);...

}

Ceci signifie que je vais (éventuellement) redéfinir la méthodeinverser dans les classes dérivées.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 18/30

Fonctions virtuelles (3)

class matrice_symetrique: public matrice_carree{// donnes priveespublic: ...

virtual inverser (...);};

class matrice_tridiagonale: public matrice_carree{// donnees priveespublic: ...

virtual inverser (...);};

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 19/30

Fonctions virtuelles (4)

Fonction virtuelle, plus que la simple surcharge: mécanisme de laliaison dynamique.

Une application peut utiliser matrice_carree sans connaître apriori les types qui seront dérivés:

void f_appli (matrice_carree& m, ...){...m.inverser (); // on travaille sur le... // type matrice_carree}

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 20/30

Page 6: 2006 2007-heritage-en-c++

Fonctions virtuelles (5)

On ira chercher à l’exécution la réalisation de inversercorrespondant au type réel de l’instance (celui de la déclaration).

int main(){matrice_tridiagonale mt;// ici on utilisera pour "inverser" dans ‘‘f_appli’’// la realisation de la classe derivee tridiagonalef_appli (mt, ..);...}

Si une fonction doit être redéfinie, utiliser une fonction virtuelle.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 21/30

Fonctions virtuelles (6)

On ira chercher à l’exécution la réalisation de la méthodecorrespondant au type réel de l’instance (celui de la déclaration).C’est pour cette raison que le destructeur doit être virtuel.N.B. le constructeur ne peut être virtuel.

Attention en cas de “simple surcharge” le choix sera fait à lacompilation.Problème: l’éventuel surcoût du mécanisme (compilateurs“dévirtualiseurs”).

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 22/30

Classe abstraite (1)

Une fonction virtuelle pure ne reçoit aucune réalisation par défaut.Une classe qui contient au moins une fonction virtuelle pure est uneclasse abstraite.

class ABSTRAITE //Notion d’archetype{...public:virtual void info(..)=0;//virtuelle pure};

Il n’est pas possible d’instancier un objet de type ABSTRAITE.Il faut écrire des classes dérivées de ABSTRAITE.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 23/30

Héritage multiple/ambiguités (1)

Toutes les ambiguités d’accès doivent être levées à la compilation:

class B_1 class B_2 class D: int main()

{... {... public B_1, {

public: public: public B_2 D vd;

int i,ii; int* ii; { vd.i ..//OK de B_1

... ... ... vd.B_1::ii//de B_1

}; }; }; vd.B_2::ii//de B_2

}

Encore une fois, :: précise le référentiel.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 24/30

Page 7: 2006 2007-heritage-en-c++

Héritage multiple/duplication (1)

Le graphe d’héritage peut amener la duplication d’une classe debase:

liste_chaînée

liste_de_A liste_de_B

dérivé_A_B

matrice_carree

matrice_symétrique_définie_positive

matrice_symétrique matrice_définie_positive

Duplication souhaitable Duplication non souhaitable

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 25/30

Héritage multiple/duplication (2)

Si on ne fait rien ==> duplication

class GP class D1 class U: int main()

{... :public GP public D1, {

public: {... public D2 U u1;

int i; }; { //GP via D1

... ... u1.D1::i ...

}; class D2 }; //GP via D2

public GP u1.D2::i ...

{... }

}; }

L’utilisation de l’opérateur :: est obligatoire pour préciser leréférentiel.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 26/30

Héritage multiple/duplication (3)

Pour éviter la duplication: notion de “classe virtuelle”.

class GP class D1: class U: int main()

{... public virtual GP public D1, {

public: {... public D2 U u1;

int i; }; { u1.i ..

... class D2: ... //un seul i

}; public virtual G }; //(de GP)

{... };

};

Problème: l’héritage virtual n’est ni une propriété de GP, ni unespécification de U.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 27/30

Récapitulation-2 (1)

Notions à bien comprendre:

Héritage simple, multiple.

privé/public/protégé .

Fonctions virtuelles.

Classes abstraites.

Classes virtuelles.

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 28/30

Page 8: 2006 2007-heritage-en-c++

C++/Conclusions (1)

La généricité est utile pour des logiciels de grande taille et dansl’optique réutilisation:

les types paramètres (template);

l’héritage simple;

l’héritage multiple (difficile à gérer).

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 29/30

C++/Conclusions (2)

Le langage C++

offre beaucoup de possibilités.

mais. . . il est aussi très “permissif”.

Il est indispensable d’avoir une méthodologie:

faire le “tri” (quelle caractéristique est utile à un momentdonné).

suivre une démarche de réalisation (les types, leursrelations mutuelles).

GIP RENATER Philippe d’Anfray Objets en C++ 2006-2007 – p. 30/30