essentiels de la POO : Encapsulation et abstraction regroupement traitements et donnes : class Rectangle { ... }; sparation entre interface et dtails dimplmentation : public, protected, private Hritage : relation est-un class Guerrier : public Personnage {...}; Polymorphisme pouvoir tre vu de plusieurs faons, abstraction, gnricit 2 ingrdients ncessaires : pointeurs et mthodes virtuelles classes abstraites et mthodes virtuelles pures Quest-ce que lhritage multiple ? En C++, une sous-classe peut hriter de plusieurs super-classes : Classe A Classe B Classe C Comme pour lhritage simple, la sous-classe hrite des super-classes : tous leurs attributs et mthodes (sauf les constructeurs/destructeurs) leur type Encore un jeu . . . Supposons que lon souhaite programmer un jeu mettant en scne les entits suivantes : 1. Balle 2. Raquette 3. Filet 4. Joueur Chaque entit sera principalement dote dune mthode evolue, grant lvolution de lentit dans le jeu. Premire bauche de conception (1) class Entite void evolue(...) class Balle class Raquette class Filet class Joueur Premire bauche de conception (2) Si lon analyse de plus prs les besoins du jeu, on ralise que : certaines entits doivent avoir une reprsentation graphique (Balle, Raquette, Filet) . . . et dautres non (Joueur) certaines entits doivent tre interactives (on veut par exemple pouvoir les contrler avec la souris) : Balle, Raquette . . . et dautres non : Joueur, Filet
Comment organiser tout cela ?
Jeu vido impossible Il nous faudrait mettre en place une hirarchie de classes telle que celle-ci : class Balle class Raquette class Filet class Joueur void evolue(...) class Entite class Interactif void gestionClic() class Graphique void dessiner()
Possible en C++ grce lhritage multiple!
Autre exemple Un exemple zoologique : Vivipare Ovipare Ovovivipare Encore un exemple ... informatique : ios ostream iostream ifstream ofstream fstream istream Hritage multiple Syntaxe : class nomSousClasse: public nomSuperClasse1, ... public nomSuperClasseN { //... }; Exemple : class Ovovivipare: public Ovipare, public Vivipare { public: Ovovivipare(unsigned int, unsigned int); virtual ~Ovovivipare(); protected: bool espece_rare; }; Lordre de dclaration des super-classes est pris en compte lors de linvocation des constructeurs/destructeurs Constructeurs/destructeurs Comme pour lhritage simple, linitialisation des attributs hrits doit tre faite par invocation des constructeurs des super-classes : Syntaxe : SousClasse(liste de paramtres) : SuperClasse1(arguments1), ... SuperClasseN(argumentsN), attribut1(valeur1), ... attributK(valeurK) {} Lorsque lune des super-classes admet un constructeur par dfaut, il nest pas ncessaire de linvoquer explicitement. Constructeurs/destructeurs (2) Attention ! Lexcution des constructeurs des super-classes se fait selon lordre de la dclaration dhritage, et non selon lordre des appels dans le constructeur ! Lordre des appels des destructeurs de super-classes est linverse de celui des appels de constructeurs Constructeurs/destructeurs : exemple class Ovovivipare : public Ovipare, public Vivipare { public: Ovovivipare(unsigned int nb_oeufs , unsigned int duree_gestation , bool rarete = false ); virtual ~Ovovivipare(); protected: bool espece_rare; }; Ovovivipare::Ovovivipare(unsigned int nb_oeufs , unsigned int duree_gestation , bool rarete) : Vivipare(duree_gestation), // Mauvais ordre !! Ovipare(nb_oeufs), espece_rare(rarete) {} Accs direct ambigu Comme dans le cas de lhritage simple, une sous-classe peut accder directement aux attributs et mthodes protgs de ses super-classes. ... et si ces attributs/mthodes portent le mme nom dans plusieurs super-classes ? class Ovipare { // ... void afficher() const; }; class Vivipare { // ... void afficher() const; }; class Ovovivipare : public Ovipare, public Vivipare { //... }; int main() { Ovovivipare o(...); o.afficher(); return 0; } Accs direct ambigu (2) Attention ! Laccs o.afficher provoquera une erreur la compilation mme si la mthode afficher navait pas les mmes paramtres dans les deux classes Ovipare et Vivipare !!! (La raison est quen C++, il ny a surcharge que dans la mme porte. Ici ce nest pas une problme de surcharge, mais un problme de masquage [rsolution de porte].) class Ovipare { // ... void afficher() const; }; class Vivipare { // ... void afficher(string const& entete) const; }; class Ovovivipare : public Ovipare, public Vivipare { //... }; int main() { Ovovivipare o(...); o.afficher("Un orvet : "); return 0; } Accs direct ambigu solutions ? Solutions ? Premire solution : utiliser loprateur de rsolution de porte. int main() { Ovovivipare o(...); o.Vivipare::afficher("Un orvet : "); return 0; } mais... Accs direct ambigu critique de la solution 1 mais... Lutilisation (externe) de loprateur de rsolution de porte pour rsoudre les ambiguts de noms des attri- buts/mthodes nest pas une bonne solution : Cest lutilisateur de la classe Ovovivipare qui dcide du fonctionnement correct de cette classe, alors que cette responsabilit doit norma- lement incomber aux concepteurs de la classe. Accs direct ambigu solution 2 Une des solutions consiste lever lambigut en indiquant explicitement dans la sous-classe quelle(s) mthode(s) on veut invoquer :
ajouter la sous-classe, une dclaration spciale indiquant quel(s)
mthode(s)/attribut(s) seront invoqu(s) exactement. Syntaxe : using NomSuperClasse::NomAttributOuMethodeAmbigu ; Exemple : class Ovovivipare : public Ovipare, public Vivipare { public: using Vivipare::afficher; // ... }; Attention ! Pas de parenthse (ni prototype) derrire le nom de la mthode! Accs direct ambigu solution 3 La meilleure solution consiste ajouter dans la sous-classe une mthode dnissant la bonne interprtation de linvocation ambigu. Exemple : class Ovovivipare: public Ovipare, public Vivipare { public: // ... void afficher() const { Ovipare::afficher(); Vivipare::afficher(" mais aussi pour sa partie" " vivipare : "); } // ... }; Classes virtuelles : problme Il peut se produire quune super-classe soit incluse plusieurs fois dans une hirarchie hritage multiple : Vivipare Ovipare Ovovivipare Animal Animal ios ostream iostream ifstream ofstream fstream istream Les attributs/mthodes de la super-classe seront inclus plusieurs fois !
Chaque objet de la classe Ovovivipare possdera deux copies
des attributs de la classe Animal. Classes virtuelles : exemple du problme class Animal { public: Animal(string const& description) : tete(description) {} protected: string tete; }; class Ovipare : public Animal { public: Ovipare() : Animal(" cornes") {} }; class Vivipare : public Animal { public: Vivipare() : Animal("de poisson") {} }; class Ovovivipare : public Ovipare, public Vivipare { public: void affiche() const { cout << "j'ai une tte " << Ovipare::tete << " et une tte " << Vivipare::tete << " !" << endl; } }; // ... Ovovivipare x; x.affiche();
jai une tte cornes et une tte de poisson !
Classes virtuelles solution Pour viter la duplication des attributs dune super-classe plusieurs fois incluse lors dhritages multiples, il faut dclarer son lien dhritage avec toutes ses sous-classes comme virtuel. Cette super-classe sera alors dite virtuelle ( ne pas confondre avec classe abstraite !!) Syntaxe : class NomSousClasse : public virtual NomSuperClasseVirtuelle Exemple : class Ovipare : public virtual Animal { // ... // ... class Vivipare: public virtual Animal { // ... A noter que cest la classe pouvant tre hrite plusieurs fois qui est virtuelle (i.e. ici la super-super-classe) et non pas directement les classes utilises dans lhritage multiple (i.e. les super-classes). Classes virtuelles (3) Vivipare Ovipare Ovovivipare Animal Un seul objet de la super-classe Animal est hrit par lhritage commun des sous-classes Ovipare et Vivipare. Constructeurs et Classes virtuelles Rappel : dans un hritage usuel, le constructeur dune sous-classe ne fait ap- pel quaux constructeurs de ses super- classes immdiates (et ceci rcursive- ment) Dans une drivation virtuelle, la super- classe virtuelle est initialise directe- ment par la sous(-sous-...)-classe ins- tancie
Toutes ses sous(-sous-...)-classes
instanciables (= non-abstraites) doivent donc faire directement appel au constructeur de la super(-super-...)-classe virtuelle Constructeurs et Classes virtuelles : Exemple Ovovivipare::Ovovivipare(string nom, Habitat habitat, Regime regime, unsigned int nb_oeufs, unsigned int gestation, bool rarete = false) : Animal(nom, habitat, regime), Ovipare(nb_oeufs), Vivipare(gestation), espece_rare(rarete) {} Classes virtuelles : appel des constructeurs Comment sont grs les appels au constructeur de la super-classe virtuelle? Ovovivipare::Ovovivipare(// ... ) : Animal(nom, habitat, regime), Ovipare(nb_oeufs), Vivipare(gestation), espece_rare(rarete) {} Vivipare Ovipare Ovovivipare Animal Ovovivipare o(...); Classes virtuelles : appel des constructeurs Lors de la cration dun objet dune classe plus drive, son constructeur invoque directement le constructeur de la super-classe virtuelle. Les appels au constructeur de la super-classe virtuelle dans les classes intermdiaires sont ignors. Si la super-classe virtuelle a un constructeur par dfaut, il nest pas ncessaire de faire appel ce constructeur explicitement. Il sera directement appel par le constructeur de la classe dont on cre une instance. Sil ny a pas dappel explicite au constructeur de la super-classe virtuelle et si celle-ci na pas de constructeur par dfaut, la compilation signalera une erreur. Ordre des constructeurs/destructeurs Dans une hirarchie de classes o il existe des super-classes virtuelles : le soin dinitialiser les super-classes virtuelles incombe la sous-classe la plus drive les constructeurs des super-classes virtuelles sont invoqus en premier les appels explicites au constructeur de la super-classe virtuelle dans les classes intermdiaires sont ignors. ceux des classes non-virtuelles le sont ensuite dans lordre de dclaration de lhritage lordre dappel des constructeurs de copie est identique lordre dappel des destructeurs est linverse de celui des appels de constructeurs