Poss0502 slides
Upcoming SlideShare
Loading in...5
×
 

Poss0502 slides

on

  • 522 views

 

Statistics

Views

Total Views
522
Views on SlideShare
522
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Poss0502 slides Poss0502 slides Presentation Transcript

  • Techniques dimplémentation de la POO en C++ statique Le paradigme objet et le C++
  • Techniques dimplémentation de la POO en C++ statique Classes, objets et messages dénition dune classe  envoi de message : convention dappel messages reconnus :  réception de message : implémentation des mé- déclaration des méthodes thodes
  • Techniques dimplémentation de la POO en C++ statiquePour la modélisation suivante : On écrit traditionnellement : ¤ class Cow { Cow public : // `Cow objects can receive // ` eat messages with an // argument of type ` Food +eat(Food&) } void eat(Food);
  • Techniques dimplémentation de la POO en C++ statique Envoi dun message : Réception par une méthode : ¤ void Cow::eat(Food& f) ¤ // send message `eat { // to object ` cow, cout  "Moo, I like that " // with argument ` grass  f  endl ; cow . eat ( grass ); }
  • Techniques dimplémentation de la POO en C++ statique Héritage et polymorphisme dénition dune relation dhé-   voir comme  : ritage références et coercion  polymorphisme dhéritage : liaison retardée : agir sur une référence vers méthodes virtuelles une classe de base
  • Techniques dimplémentation de la POO en C++ statiquePour la modélisation suivante : On écrit traditionnellement : ¤ class Herbivor { public : virtual void eat(Food&) = 0; }; class Cow : public Herbivor { public : Herbivor void eat(Food&); +eat(Food&) } class Sheep : public Herbivor { public : Cow Sheep void eat(Food&); +eat(Food&) +eat(Food&) }
  • Techniques dimplémentation de la POO en C++ statique Démonstration de la liaison Alorithme polymorphe : ¤ retardée : void Farmer:: feed( Herbivor& thingy) ¤ // ` thingy is a reference to { // an object of base class Grass g; // ` Herbivor thingy . eat(g); } thingy . eat ( grass ); // [...] farmer . feed(cow); farmer . feed(sheep ); // [...] Lappel est résolu par liaison retardée.
  • Techniques dimplémentation de la POO en C++ statique Mais... 1 invocation dune méthode  les règles de typage im- virtuelle ⇒ 1 indirection pour posent une coercion dangeu- obtenir son adresse avant reuse pour des cas de modé- lappel lisation courants le compilateur na pas la pos-  on voudrait des  types vir- sibilité dinliner les méthodes tuels 
  • Techniques dimplémentation de la POO en C++ statique Objectifs : Moyens mis en ÷uvre : résoudre statiquement la liai-  la méta-programmation son retardée  le polymorphisme paramé- conserver, si possible, le trique  sucre syntaxique  du C++ ⇒ utiliser les templates du le code doit exprimer la mo- C++ pour faire de la délisation théorique Méta-POO
  • Techniques dimplémentation de la POO en C++ statique Première approche et introduction aux techniques
  • Techniques dimplémentation de la POO en C++ statique Objectif :  instruire  la classe de base. Première modélisation : Implémentation : ¤ template<typename Exact> class Herbivor SubClass { Herbivor public : void eat(Food&); } ¤ template<typename Exact> Herbivor<Cow> void Herbivor<Exact>::eat(Food& f) { // emulate method dispatching // with controlled coercion Cow static_cast<Exact∗>(this)−>eat(f); } ¤ Herbivor<Sheep> class Cow : public Herbivor<Cow> { /∗ no change ∗/ } class Sheep : public Herbivor<Sheep> Sheep { /∗ no change ∗/ }
  • Techniques dimplémentation de la POO en C++ statique Héritage statique : polymorphisme dhéritage par le polymorphisme paramétrique contraint. Lalgorithme polymorphe : ... devient : ¤ template<typename Any> ¤void Farmer:: feed( Herbivor& thingy) void Farmer:: feed( Herbivor<Any>& thingy){ { Grass g; Grass h; thingy . eat(g); thingy . eat(g);} }
  • Techniques dimplémentation de la POO en C++ statique Avantages : Inconvénients :  mécanismes syntaxiques non idiomatiques lexpression des implémenta-  templates longs à compiler tion nest pas modiée  multiplication cartésienne des on conserve la modélisation instances : le compilateur peut inliner (classesf illes) × (classesmeres)
  • Techniques dimplémentation de la POO en C++ statique Le code  classique  : Le code  statique  : ¤ template<typename Exact> struct IntFunc { ¤ int apply( int x)struct IntFunc { return dispatch (apply )(x ); }{ // dispatch is a macro virtual int apply( int x) = 0; };}; struct Annulate : IntFunc<Annulate>struct Annulate : IntFunc {{ int apply( int x) int apply( int x) { return 0; } { return 0; } };}; template<typename Any>void many_applies(const unsigned N, void many_applies(const unsigned N, IntFunc& f, IntFunc<Any>& f, int x) int x){ { for (unsigned i = 0; i < N; ++i) for (unsigned i = 0; i < N; ++i) f . apply(x ); f . apply(x );}; };
  • Techniques dimplémentation de la POO en C++ statique Après optimisation par GCC : 7 classic paradigm static paradigm 6 5 iteration time, in seconds 4 3 2 1 0 0 2e+07 4e+07 6e+07 8e+07 1e+08 N
  • Techniques dimplémentation de la POO en C++ statique Les vaches mangent de lherbe...
  • Techniques dimplémentation de la POO en C++ statique ... alias la contravariance des arguments. Food Implémentation classique : ¤ struct Food { /∗ ... ∗/ }; struct Grass : Food { /∗ ... ∗/ }; struct Animal Grass { virtual void eat(Food&) = 0; }; struct Cow : Animal Animal { // declaring eat(Grass&) violates +eat(Food&) // the contravariance void eat(Food& f) { // not safe , not ecient : Grass& g = dynamic_cast<Grass&>(f); Cow /∗ ... ∗/ } +eat(Grass&) };
  • Techniques dimplémentation de la POO en C++ statique en utilisant lhéritage statique, ce code devient... dune part : et dautre part : ¤ template<typename SubClass> struct Animal { template<typename F> void eat(Food<F>& f) { dispatch (eat)( static_cast<F&>(f)); } }; struct Cow : Animal<Cow> ¤{template<typename SubClass> void eat(Grass& g)struct Food {{ /∗ ... ∗/ }; cout  "Moo, I love grass."  endl ;struct Grass : Food<Grass> }{ /∗ ... ∗/ }; }; Cette version est correctement typée !
  • Techniques dimplémentation de la POO en C++ statique Le compilateur rejette eectivement les cas invalides : ¤ /∗ ... ∗/Meat m;Animal<Cow>& a = cow;a . eat(m); donne : ¤contra .cc : In member function ` void Animal<SubClass>::eat(Food<Any>&) [ with Any = Meat, SubClass = Cow]:contra .cc :35: instantiated from ` void feed(Animal<AnyAnimal>&, Food<AnyFood>&) [with AnyAnimal = Cow, AnyFood = Meat]contra .cc :44: instantiated from herecontra .cc :18: no matching function for call to ` Cow::eat(Meat&)contra .cc :26: candidates are : void Cow::eat(Grass&)
  • Techniques dimplémentation de la POO en C++ statique Séparation interface/dénition, classes abstraites
  • Techniques dimplémentation de la POO en C++ statique Ce code nest pas correct : ¤ Celui-ci lest :template<typename Exact> ¤struct BaseClass template<typename Exact>{ struct BaseClass void m() { { void m() // dispatch to Exact :: m { static_cast<Exact∗>(this) // dispatch to Exact :: m_impl −>m(); static_cast<Exact∗>(this) } −>m_impl();}; } };struct Deriv : BaseClass<Deriv>{ /∗ m not implemented ∗/}; ⇒ le compilateur peut détecter ⇒ au lieu dun message derreur, le loubli dimplémentation dans la compilateur génère une récursion innie. classe dérivée. Deux eets : un problème corrigé et une séparation de noms entre interface et implémentation.
  • Techniques dimplémentation de la POO en C++ statique Ce code nest pas correct : ¤ Celui-ci lest : ¤template<typename Exact> template<typename Exact>struct AbstractClass struct AbstractClass{ { void m(); void m();}; protected:// [...] ~AbstractClass (); AbstractClass <Foo> foo; };// [...]⇒ le compilateur permet dinstancier ⇒ le compilateur interdit une classe abstraite linstanciation de la classe On simule les classes abstraites en protégeant le destructeur.
  • Techniques dimplémentation de la POO en C++ statique Ajout de niveaux de hiérarchie supplémentaires
  • Techniques dimplémentation de la POO en C++ statique Pour la hiérarchie suivante : On peut pratiquer trois méthodes :  Méthode R Animal +eat(Food&) ⇒ la classe de base connaît la classe immédiatement infé- Herbivor +eat(Grass&) rieure  Méthodes S1 et S2 Cow Sheep ⇒ la classe de base connaît le +eat(Grass&) +eat(Grass&) type exact
  • Techniques dimplémentation de la POO en C++ statique La méthode R dhéritage statique
  • Techniques dimplémentation de la POO en C++ statique Avec la méthode R, on indique à chaque dérivation le type dérivé à la classe-mère : Herbivor_<Cow_<Inf>> Inf Animal_ +eat(Food<Any>&) Inf #~Animal_() Cow_ +eat(Grass<Any>&) Animal_<Herbivor_<Inf>> Herbivor_<Sheep_<Inf>> Inf Herbivor_ Inf +eat(Grass<Any>&) Sheep_ #~Herbivor_() +eat(Grass<Any>&)
  • Techniques dimplémentation de la POO en C++ statique Pour instancier une classe, on utilise un type bottom (⊥) : ¤ ¤typedef Cow_<bottom> Cow; typedef Sheep_<bottom> Sheep; Animal_<Herbivor_<Cow_<bottom>>> Animal_<Herbivor_<Sheep_<bottom>>> Herbivor_<Cow_<bottom>> Herbivor_<Sheep_<bottom>> Cow = Cow_<bottom> Sheep = Sheep_<bottom>
  • Techniques dimplémentation de la POO en C++ statique Le type exact de nimporte quel objet peut être retrouvé à la compilation :find exact (C) = C si inferior (C) = ⊥ find exact ( inferior (C) ) sinon. Cette formule est implémentée par templates récursifs.
  • Techniques dimplémentation de la POO en C++ statique la méthode R Avantages : Inconvénients : le type des classes donne des  les messages derreur de ty- informations sur la hiérarchie page sont très complexes linstanciation des classes  limplémentation de find exact  terminales  est facile à est coûteuse en temps de laide de ⊥ compilation
  • Techniques dimplémentation de la POO en C++ statique La méthode S1 dhéritage statique
  • Techniques dimplémentation de la POO en C++ statiqueAvec la méthode S1, on indique à chaque instanciation le type exact à la hiérarchie : Exact Herbivor_<Exact> Animal_ +eat(Food<Any>&) #~Animal_() Exact Cow_ +eat(Grass<Any>&) Animal_<Exact> Herbivor_<Exact> Exact Herbivor_ Exact +eat(Grass<Any>&) Sheep_ #~Herbivor_() +eat(Grass<Any>&)
  • Techniques dimplémentation de la POO en C++ statique Pour instancier une classe de la hiérarchie, il faut la dériver : ¤ ¤class Cow : public Cow_<Cow> class Sheep : public Sheep_<Sheep>{ /∗ ... ∗/ } { /∗ ... ∗/ } Animal_<Cow> Animal_<Sheep> Herbivor_<Cow> Herbivor_<Sheep> Cow_<Cow> Sheep_<Sheep> Cow Sheep
  • Techniques dimplémentation de la POO en C++ statique En C++, les constructeurs ne sont pas hérités : ¤ ¤template<typename Exact> class Cow : public Cow_<Cow>class Cow_ : public Herbivor_<Exact> {{ public :public : template<typename Any> template<typename Any> Cow(Cow_<Any>& mother, Cow_(Cow_<Any>& mother, Cow_<Any>& father) Cow_<Any>& father) /∗ dispatch to parent class ∗/ { /∗ birth code ∗/ } : Cow_<Cow>(mother, father) {} // ...} } Le(s) constructeur(s) doivent être recopiés à la dérivation.
  • Techniques dimplémentation de la POO en C++ statique la méthode S1 Avantages : Inconvénients :  la création dun type ins- pas de coût pour retrouver le tanciable implique la création type exact dans la classe de dune nouvelle classe base  le compilateur nempêche pas les messages derreur de de dériver une classe abstraite typage sont (relativement) de la hiérarchie pour créer un simples type instanciable
  • Techniques dimplémentation de la POO en C++ statique La méthode S2 dhéritage statique
  • Techniques dimplémentation de la POO en C++ statique Avec la méthode S2, on indique à chaque instanciation un traits vers le type exact à la hiérarchie : ExactFinder Animal_ Herbivor_<ExactFinder> +Exact = ExactFinder::ret +eat(Food<Any>&) ExactFinder #~Animal_() Cow_ +eat(Grass<Any>&) Animal_<ExactFinder> Herbivor_<ExactFinder> ExactFinder Herbivor_ +eat(Grass<Any>&) ExactFinder #~Herbivor_() Sheep_ +eat(Grass<Any>&)
  • Techniques dimplémentation de la POO en C++ statiquePour instancier une classe, il faut construire les traits adéquats : ¤ ¤struct IsCow struct IsSheep{ { typedef Cow_<IsCow> ret; typedef Sheep_<IsSheep> ret;}; };typedef IsCow:: ret Cow; typedef IsSheep :: ret Sheep; IsCow +ret = Cow_<IsCow> IsSheep +ret = Sheep_<IsSheep> Animal_<IsCow> Animal_<IsSheep> Herbivor_<IsCow> Herbivor_<IsSheep> Cow = Cow_<IsCow> Sheep = Sheep_<IsSheep>
  • Techniques dimplémentation de la POO en C++ statique On peut même automatiser la création de ExactFinder : T:template <class> class Make +ret = T<Make<T>> Cow = Make<Cow_>::ret Sheep = Make<Sheep_>::ret ¤template<template<class> class T>struct Make{ typedef T<Make<T> > ret;};typedef Make<Sheep_>::ret Sheep;typedef Make<Cow_>::ret Cow;
  • Techniques dimplémentation de la POO en C++ statique Si une classe de la hiérarchie est  plus  paramétrée, il faut agrandir Make : T:template<class,class> class Arg1 Make1 +ret = T<Make1<T, Arg1>, Arg1> T:template<class,class,class> class Arg1 Arg2 Make2 +ret = T<Make2<T, Arg1, Arg2>, Arg1, Arg2>
  • Techniques dimplémentation de la POO en C++ statique la méthode S2 Avantages : Inconvénients : pas de coût pour retrouver le  les messages derreurs de type exact dans la classe de typage sont moins simples base quavec la méthode S1 la création dun type instan-  on ne peut pas entièrement ciable est plus simple quavec automatiser la création du la méthode S1 ExactFinder
  • Techniques dimplémentation de la POO en C++ statique Un détour chez les types virtuels
  • Techniques dimplémentation de la POO en C++ statique Objectifs : Mais... équipper les hiérarchies avec  le typage du C++ empêche les  types virtuels  une implémentation triviale garder une approche systé-  la sémantique des types vir- matique de lhéritage statique tuels est encore mal dénie
  • Techniques dimplémentation de la POO en C++ statique Modélisation souhaitée : T Container +iterator: virtual type +begin(): iterator +end(): iterator +contains(T&): bool T T List Vector +iterator = list_iterator<T> +iterator = vector_iterator<T> +begin(): list_iterator<T> +begin(): vector_iterator<T> +end(): list_iterator<T> +end(): vector_iterator<T> +contains(T&): bool +contains(T&): bool
  • Techniques dimplémentation de la POO en C++ statique Avec héritage statique : Container_<exact_of(List, X, T) > X T Container_ X T +Exact = to_exact(X) List_ +iterator = virtual_type(Exact, iterator) +begin(): iterator +iterator = list_iterator<T> +end(): iterator +begin(): list_iterator<T> +contains(T&): bool +end(): list_iterator<T> #~Container() +contains(T&): bool to exact et exact of dépendent de la méthode dhéritage virtual type reste à dénir
  • Techniques dimplémentation de la POO en C++ statique Une implémentation triviale... ¤#dene virtual_type(ExactType, Name) typename ExactType::Nametemplate<typename Exact, typename T>struct Container_{ typedef virtual_type (Exact, iterator ) iterator ; iterator begin() { return dispatch (begin )(); } // ...};template<typename Exact, typename T>struct List_ : Container_<Exact, T>{ typedef list_iterator <T> iterator; // dened elsewhere iterator begin_impl() { /∗ ... ∗/ } // ...};// derivation to instanciate the classtemplate<typename T> struct List : List_<List<T>, T> {};
  • Techniques dimplémentation de la POO en C++ statique ... ne fonctionne pas : ¤// [...] List <int> l; // line 36 List <int>:: iterator i = l . begin ();// [...] donne à la compilation : ¤triv_vt .cc : In instantiation of ` Container_<List<int>, int>:triv_vt .cc :36: instantiated from `List_<List<int>, int>triv_vt .cc :36: instantiated from ` List <int>triv_vt .cc :36: instantiated from heretriv_vt .cc :9: no type named ` iterator in ` struct List <int>triv_vt .cc :12: no type named ` iterator in ` struct List <int> À linstanciation de Container , la dénition du type nest pas encore connue.
  • Techniques dimplémentation de la POO en C++ statique Pour résoudre le problème, on doit séparer la dénition des types virtuels de la hiérarchie statique. Avec les méthodes R et S1,  Avec la méthode S2, on peut soit :  recourir à une hiérarchie on a recours à une hiérarchie parallèle  faire porter les types vir- de traits parallèle tuels par le ExactFinder
  • Techniques dimplémentation de la POO en C++ statique Avec une hiérarchie parallèle, on obtient la modélisation suivante : X T Container +Exact = to_exact(X) +iterator = vt_trait<Exact>::iterator Container_<exact_of(List, X, T)> vt_trait<Container_<...>> X X T T vt_trait<List_<...>> List_ +iterator = list_iterator<T> dépend de la méthode d’héritage
  • Techniques dimplémentation de la POO en C++ statiqueIl ny a quun traits, mais ses spécialisations sont hiérarchisées : Exact vt_trait<Animal<Exact>> Ce mécanisme est nécessaire pour pouvoir dénir les types Exact virtuels à des niveaux vt_trait<Herbivor_<Exact>> intermédiaires de la hiérarchie +FoodType = Grass Exact vt_trait<Cow_<Exact>>
  • Techniques dimplémentation de la POO en C++ statiqueAvantages de cette méthode : Inconvénients :  nécessite une séparation permet dexprimer les besoins entre la dénition de la classe et celle de ses types virtuels courants  on connaît mal la portée sé- application systématique mantique de cette construc- (donc automatisable) tion
  • Techniques dimplémentation de la POO en C++ statique Conclusion